Posting ini adalah bagian dari serangkaian artikel tentang tujuan baris. Anda dapat menemukan bagian lain di sini:
- Bagian 1:Menetapkan dan Mengidentifikasi Sasaran Baris
- Bagian 2:Semi Bergabung
Bagian ini mencakup kapan dan mengapa pengoptimal memperkenalkan sasaran baris untuk anti gabung.
Pengantar
Anti join juga dikenal sebagai anti semi join. Ini mengembalikan setiap baris dari input gabungan A yang tidak cocok dapat ditemukan di input B.
Untuk anti bergabung:
- Pengoptimal mungkin tambahkan sasaran baris sisi dalam ke terapkan (penggabungan loop bersarang berkorelasi) hanya anti gabung .
- Sasaran baris tidak ditambahkan untuk loop bersarang yang tidak berkorelasi anti join, hash anti join, atau merge anti join.
- Seperti biasa, setiap sasaran baris hanya ditambahkan jika lebih rendah dari perkiraan tanpa sasaran baris diterapkan.
- Sisi dalam yang berlebihan
TOP
klausa danDISTINCT/GROUP BY
operasi dapat disederhanakan.
Memperluas poin pertama di atas, perbedaan utama antara tujuan menerapkan semi join dan menerapkan anti join baris adalah:
- Sebuah terapkan semi-gabung selalu menampilkan sasaran baris (asalkan kurang dari perkiraan tanpa tujuan).
- Sebuah menerapkan anti gabung dapat menampilkan sasaran baris , tetapi hanya jika anti gabungan logis diubah menjadi penerapan selama pengoptimalan berbasis biaya .
Saya minta maaf bahwa aturan ini tidak sederhana, tetapi saya tidak membuatnya. Semoga beberapa diskusi dan contoh akan memperjelas semuanya.
Tidak Ada Sasaran Baris Anti Gabung Secara Default
Pengoptimal mengasumsikan bahwa orang menulis setengah bergabung (secara tidak langsung misalnya menggunakan EXISTS
) dengan harapan bahwa baris yang dicari akan ditemukan . sasaran baris diterapkan semi-gabung telah ditetapkan oleh pengoptimal untuk membantu menemukan baris yang cocok dengan yang diharapkan dengan cepat.
Untuk anti bergabung (dinyatakan misalnya menggunakan NOT EXISTS
) asumsi pengoptimal adalah bahwa baris yang cocok tidak akan ditemukan . sasaran baris penerapan anti gabung tidak ditetapkan oleh pengoptimal, karena mengharapkan harus memeriksa semua baris untuk memastikan tidak ada yang cocok.
Jika ternyata ada baris yang cocok, penerapan anti gabung mungkin membutuhkan waktu lebih lama untuk menemukan baris ini daripada jika sasaran baris telah digunakan. Namun demikian, anti join akan tetap menghentikan pencariannya segera setelah kecocokan (tidak terduga) ditemukan.
Terapkan Ketentuan Sasaran Baris Anti Gabung
SQL Server tidak memberi kami cara untuk menulis anti join secara langsung, jadi kami harus menggunakan solusi seperti NOT EXISTS
, NOT IN/ANY/SOME
, atau EXCEPT
. Masing-masing formulir ini menghasilkan representasi subquery di pohon yang diuraikan di awal kompilasi kueri. Subkueri ini selalu dibuka menjadi aplikasi, lalu diubah menjadi anti gabung logis jika memungkinkan (detailnya sama dengan semi join yang dibahas di part 2). Ini semua terjadi bahkan sebelum rencana sepele dipertimbangkan.
Agar anti bergabung untuk mendapatkan sasaran baris, ia harus masuk pengoptimalan berbasis biaya sebagai anti gabung logis (artinya transformasi dari aplikasi di atas pasti berhasil). Kemudian, pengoptimal berbasis biaya harus memilih untuk menerapkan anti gabung logis sebagai berlaku . Agar hal ini terjadi, pengoptimal pertama-tama harus memilih untuk menjelajah opsi terapkan; maka harus memilih itu sebagai opsi termurah (untuk bagian paket itu).
Sasaran baris anti-gabung ditetapkan oleh salah satu aturan pengoptimalan berbasis biaya yang dapat mengubah gabungan menjadi penerapan. Anti bergabung yang masuk pengoptimalan berbasis biaya sebagai penerapan (karena transformasi ke logika anti join gagal) tidak menerapkan sasaran baris.
Pengoptimal berbasis biaya hanya akan menjelajahi dan memilih opsi gabung-untuk-menerapkan jika ada cara yang efisien untuk menemukan setiap baris sisi dalam yang cocok (misalnya menggunakan indeks). Pengoptimal tidak akan menjelajahi opsi jika subpohon sisi dalam gabungan tidak memiliki sesuatu yang berguna untuk predikat penerapan ke "latch on to". Ini mungkin sebuah indeks, indeks sementara (melalui spool indeks bersemangat), atau kunci logis lainnya. Menambahkan sasaran baris membantu pengoptimal menilai biaya opsi gabung-untuk-menerapkan mengingat maksimum satu baris perlu ditempatkan.
Perhatikan bahwa penerapan anti gabung dapat muncul dalam rencana eksekusi tanpa tujuan baris. Ini terjadi ketika transformasi awal dari apply ke join gagal, seperti yang biasa terjadi. Saat ini terjadi, anti gabung akan mulai aktif di pengoptimal berbasis biaya sebagai penerapan, sehingga tidak pernah memiliki sasaran baris yang ditambahkan oleh salah satu aturan gabung untuk mendaftar.
Tentu saja tujuan baris juga dapat diperkenalkan di sisi dalam penerapan ini melalui mekanisme yang berbeda (tidak terkait dengan penerapan), misalnya oleh operator Top yang terpisah.
Untuk meringkas:
- Anti bergabung hanya dapat memperoleh sasaran baris selama pengoptimalan berbasis biaya (CBO).
- Aturan yang menerjemahkan anti gabung ke penerapan menambahkan sasaran baris.
- Anti join harus masuk CBO sebagai join, bukan apply.
- Untuk masuk ke CBO sebagai join, fase sebelumnya harus bisa menulis ulang subquery sebagai join (melalui tahap apply).
- CBO hanya mengeksplorasi gabungan untuk menerapkan transformasi dalam kasus yang menjanjikan.
Contoh
Sedikit lebih sulit untuk mendemonstrasikan semua ini untuk apply anti join daripada yang terjadi untuk apply semi join. Alasan untuk ini akan dibahas di bagian 4.
Sementara itu, berikut adalah contoh AdventureWorks yang menunjukkan bagaimana penerapan anti gabung dengan tujuan baris muncul, menggunakan tanda jejak tidak terdokumentasi yang sama seperti untuk semi gabung. Tanda jejak 8608 ditambahkan untuk menunjukkan struktur memo awal di awal pengoptimalan berbasis biaya.
SELECT P.ProductID FROM Production.Product AS P WHERE NOT EXISTS ( SELECT 1 FROM Production.TransactionHistoryArchive AS THA WHERE THA.ProductID = P.ProductID UNION ALL SELECT 1 FROM Production.TransactionHistory AS TH WHERE TH.ProductID = P.ProductID ) OPTION (QUERYTRACEON 3604, QUERYTRACEON 8607, QUERYTRACEON 8608, QUERYTRACEON 8612, QUERYTRACEON 8621);
Subquery yang ada pertama kali ditransformasikan ke apply: