NOT EXISTS ile NOT IN ve LEFT NERAS NEREDE NEREDE GİRİLİR?


151

Bana öyle geliyor ki DEĞİL, DEĞİL, IN veya LEFT JOER NULL NEREDE kullanarak bir SQL sorgusu yapabilirsiniz. Örneğin:

SELECT a FROM table1 WHERE a NOT IN (SELECT a FROM table2)

SELECT a FROM table1 WHERE NOT EXISTS (SELECT * FROM table2 WHERE table1.a = table2.a)

SELECT a FROM table1 LEFT JOIN table2 ON table1.a = table2.a WHERE table1.a IS NULL

Tüm sözdizimini doğru alıp almadığımdan emin değilim, ama bunlar genel olarak gördüğüm teknikler. Neden birini diğerinin üzerinde kullanmayı seçeyim ki? Performans farklı mı ...? Bunlardan hangisi en hızlı / en verimli? (Uygulamaya bağlıysa, her birini ne zaman kullanırım?)


6
Birçok yaygın SQL motoru size bir yürütme planı görme olanağı sağlar. Bu şekilde mantıksal olarak eşdeğer sorgular için genellikle verimlilikte önemli farklılıklar tespit edebilirsiniz. Herhangi bir yöntemin başarısı, tablo boyutu, hangi indekslerin mevcut olduğu ve diğerleri gibi faktörlere bağlıdır.
Chris Farmer

2
@wich: hiçbir veritabanı, EXISTSmadde içinde tam olarak ne döndürdüğünüzü umursamaz . Geri dönebilirsiniz *, NULLya da her neyse: tüm bunlar optimize edilecektir.
Quassnoi

2
@wich - neden? Her ikisi de burada: techonthenet.com/sql/exists.php ve burada: msdn.microsoft.com/en-us/library/ms188336.aspx * *
froadie

8
@wich: Bu "ilgiyi ifade etmek" ile ilgili değil. Bu ayrıştırıcı SELECTve arasında bir şey koymanızı talep ettiği sorgu ile ilgilidir FROM. Ve yazmak *daha kolaydır. Evet, SQLdoğal bir dile benzerlik gösterir, ancak bir makine, programlanmış bir makine tarafından ayrıştırılır ve yürütülür. Bu, aniden kablonuza girip "bir EXISTSsorgudaki fazladan alanları talep etmeyi durdurun çünkü onları ayrıştırmaktan ve sonra atmaktan bıktım!" Diye bağırmayacak . Gerçekten bir bilgisayarla sorun yok.
Quassnoi

1
@Quassnoi, kodu yalnızca makinenin yorumlaması amacıyla kod yazdıysanız, kodun korkunç görüneceğini ve ne yazık ki çok az insan böyle çalıştığını söyledi. Bununla birlikte, başka bir optikte kod yazarsanız, makinenin akranlarınıza bir tebliğ olarak yapmasını istediğinizi ifade etmek için kod yazmanız durumunda, daha iyi ve daha sürdürülebilir bir kod yazacaksınız. Akıllı olun, insanlar için kod yazın, bilgisayar için değil.
wich

Yanıtlar:


139

Kısaca:

NOT INbiraz farklıdır: NULLlistede tek bir öğe varsa hiçbir zaman eşleşmez .

  • İçinde MySQL, NOT EXISTSbiraz daha az verimli

  • İçinde SQL Server, LEFT JOIN / IS NULLdaha az verimlidir

  • İçinde PostgreSQL, NOT INdaha az verimlidir

  • İçinde Oracle, her üç yöntem de aynıdır.


1
Bağlantılar için teşekkürler! Ve hızlı genel bakış için teşekkürler ... Ofisim herhangi bir nedenden dolayı bağlantıyı engelliyor: P ama normal bir bilgisayara ulaşır ulaşmaz kontrol edeceğim.
froadie

2
Başka bir nokta ise olmasıdır table1 .aiçeren sorgu bu satırı ancak döndürmez eğer sorgu irade boştur. NOT IN ve NOT EXISTS Sıfırlanabilir Sütunlar: SQL ServerNULLEXISTSNOT INtable2
Martin Smith

@MartinSmith: tıpkı NULL NOT IN ()gerçek (değil NULL) olarak değerlendirirNOT EXISTS (NULL = column)
Quassnoi

2
@Quassnoi - er, İyi bir nokta, yanlış yöne döndü. Her NOT EXISTSzaman satırı döndürür, ancak NOT INyalnızca alt sorgu satır döndürmezse bunu yapar.
Martin Smith

5

Veritabanı sorguyu optimize etmede iyi ise, ilk ikisi üçüncüye yakın bir şeye dönüştürülecektir.

Sorunuzdakiler gibi basit durumlar için, hepsi birleşim olarak yürütüleceğinden, çok az veya hiç fark olmamalıdır. Daha karmaşık sorgular olarak, veritabanı üzerinden katılmak yapmak mümkün olmayabilir not inve not existsqueryes. Bu durumda, sorgular çok daha yavaş olacaktır. Öte yandan, kullanılabilecek bir dizin yoksa bir birleştirme de kötü performans gösterebilir, bu nedenle bir birleştirme kullandığınız için güvenli olduğunuz anlamına gelmez. Performans sorunları olup olmadığını anlamak için sorgunun yürütme planını incelemeniz gerekir.


2

Boş değerlerden kaçındığınızı varsayarsak, bunların tümü Standart SQL kullanarak bir anti-join yazmanın yoludur .

Açık bir ihmal aşağıdakileri kullanarak eşdeğerdir EXCEPT:

SELECT a FROM table1
EXCEPT
SELECT a FROM table2

Oracle'da MINUSoperatörü kullanmanız gerektiğini unutmayın (muhtemelen daha iyi bir ad):

SELECT a FROM table1
MINUS
SELECT a FROM table2

Özel sözdiziminden bahsetmişken, örneğin OUTER APPLYSQL Server'da kullandığınız ürüne bağlı olarak araştırmaya değer Standart olmayan eşdeğerler de olabilir (örneğin):

SELECT t1.a
  FROM table1 t1
       OUTER APPLY 
       (
        SELECT t2.a
          FROM table2 t2
         WHERE t2.a = t1.a
       ) AS dt1
 WHERE dt1.a IS NULL;

0

Çok alanlı birincil anahtar ile tabloya veri eklemeniz gerektiğinde, çok daha hızlı olacağını düşünün (Access'te denedim, ancak herhangi bir Veritabanında düşünüyorum) "tablodaki 'bu tür' değerlere sahip kayıtlar yok", - daha ziyade sadece tabloya yerleştirin ve fazla kayıtlar (anahtar ile) iki kez eklenmeyecektir.


0

Performans perspektifi her zaman NOT IN, EXISTS, gibi ters anahtar kelimeler kullanmaktan kaçının ... Ters öğeleri kontrol etmek için DBMS kullanılabilir tüm aracılığıyla çalışır ve ters seçimi bırakın çünkü.


1
Ve gerçekten ihtiyacınız olduğunda geçici çözüm olarak ne öneriyorsunuz NOT?
dnoeth

Neden bir seçenek olmadığında NOT işlemlerini kullanmamız gerekiyor ve bu yüzden varlar. En iyi uygulama, başka alternatif çözümlerimiz olduğunda bunlardan kaçınmaktır.
Lahiru Cooray

@onedaywhen, bir optimizer bir sorguyu dönüştürür ve yanlış sonucu döndürürse bir hatadır
David דודו Markovitz

@DuduMarkovitz: evet ve SQL Server ekibiyle iletişime geçerseniz ve hatayı kabul ederler, ancak bunu yapmanın sorguları daha yavaş çalıştırabileceğini söyledikleri için düzeltmeyi reddederseniz, uğraşmanız gereken bir hatadır .
oneday10

@onedaywhen - Bu varsayım varsayımsal bir senaryo değildi :-) Hiç hata detaylarını hatırlıyor musun?
David דודו Markovitz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.