Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

TIDAK DI vs TIDAK ADA

Saya selalu default ke NOT EXISTS .

Rencana eksekusi mungkin sama saat ini tetapi jika salah satu kolom diubah di masa mendatang untuk mengizinkan NULL adalah NOT IN versi perlu melakukan lebih banyak pekerjaan (bahkan jika tidak ada NULL s sebenarnya ada dalam data) dan semantik NOT IN jika NULL s adalah hadiah tidak mungkin menjadi yang Anda inginkan.

Bila tidak ada Products.ProductID atau [Order Details].ProductID izinkan NULL adalah NOT IN akan diperlakukan sama dengan kueri berikut.

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId) 

Paket yang tepat dapat bervariasi tetapi untuk contoh data saya, saya mendapatkan yang berikut ini.

Kesalahpahaman yang cukup umum tampaknya bahwa sub kueri yang berkorelasi selalu "buruk" dibandingkan dengan gabungan. Mereka pasti bisa ketika mereka memaksa rencana loop bersarang (sub query dievaluasi baris demi baris) tetapi rencana ini menyertakan operator logika anti semi join. Penggabungan anti semi tidak terbatas pada loop bersarang tetapi dapat menggunakan hash atau gabungan (seperti dalam contoh ini) juga.

/*Not valid syntax but better reflects the plan*/ 
SELECT p.ProductID,
       p.ProductName
FROM   Products p
       LEFT ANTI SEMI JOIN [Order Details] od
         ON p.ProductId = od.ProductId 

Jika [Order Details].ProductID adalah NULL -bisa querynya jadi

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId)
       AND NOT EXISTS (SELECT *
                       FROM   [Order Details]
                       WHERE  ProductId IS NULL) 

Alasan untuk ini adalah bahwa semantik yang benar jika [Order Details] berisi NULL ProductId s adalah untuk tidak mengembalikan hasil. Lihat ekstra anti semi join dan spool jumlah baris untuk memverifikasi ini yang ditambahkan ke paket.

Jika Products.ProductID juga diubah menjadi NULL -bisa querynya jadi

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId)
       AND NOT EXISTS (SELECT *
                       FROM   [Order Details]
                       WHERE  ProductId IS NULL)
       AND NOT EXISTS (SELECT *
                       FROM   (SELECT TOP 1 *
                               FROM   [Order Details]) S
                       WHERE  p.ProductID IS NULL) 

Alasan untuk itu adalah karena NULL Products.ProductId tidak boleh dikembalikan dalam hasil kecuali jika NOT IN sub kueri tidak memberikan hasil sama sekali (yaitu [Order Details] meja kosong). Dalam hal ini seharusnya. Dalam rencana untuk sampel data saya ini diterapkan dengan menambahkan anti semi join lainnya seperti di bawah ini.

Efek dari ini ditunjukkan dalam posting blog yang sudah ditautkan oleh Buckley. Dalam contoh di sana, jumlah pembacaan logis meningkat dari sekitar 400 menjadi 500.000.

Selain itu fakta bahwa satu NULL dapat mengurangi jumlah baris menjadi nol membuat estimasi kardinalitas menjadi sangat sulit. Jika SQL Server mengasumsikan bahwa ini akan terjadi tetapi sebenarnya tidak ada NULL baris dalam data sisa rencana eksekusi mungkin menjadi bencana yang lebih buruk, jika ini hanya bagian dari kueri yang lebih besar, dengan loop bersarang yang tidak sesuai yang menyebabkan eksekusi berulang dari sub pohon yang mahal misalnya.

Ini bukan satu-satunya rencana eksekusi yang mungkin untuk NOT IN pada NULL kolom -mampu namun. Artikel ini menunjukkan satu lagi untuk kueri terhadap AdventureWorks2008 basis data.

Untuk kode NOT IN pada NOT NULL kolom atau NOT EXISTS terhadap kolom nullable atau non nullable itu memberikan rencana berikut.

Ketika kolom berubah menjadi NULL -bisa NOT IN rencana sekarang terlihat seperti

Ini menambahkan operator bergabung dalam ekstra untuk rencana tersebut. Perangkat ini dijelaskan di sini. Semuanya ada di sana untuk mengonversi pencarian indeks berkorelasi tunggal sebelumnya di Sales.SalesOrderDetail.ProductID = <correlated_product_id> untuk dua pencarian per baris luar. Yang tambahan ada di WHERE Sales.SalesOrderDetail.ProductID IS NULL .

Karena ini berada di bawah anti semi join jika yang mengembalikan baris apa pun, pencarian kedua tidak akan terjadi. Namun jika Sales.SalesOrderDetail tidak mengandung NULL ProductID s itu akan menggandakan jumlah operasi pencarian yang diperlukan.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara MEMPERBARUI dari SELECT di SQL Server

  2. Kesalahan MSSQL 'Penyedia yang mendasari gagal saat Buka'

  3. Dapatkan Info Kolom untuk Tabel atau Tampilan di SQL Server (T-SQL:sp_columns)

  4. Bagaimana ISNUMERIC() Bekerja di SQL Server

  5. Bagaimana cara mengubah nilai kolom identitas secara terprogram?