SQL Server IN ve EXISTS Performansı


115

Aşağıdakilerden hangisinin daha verimli olacağını merak ediyorum?

Kullanım konusunda her zaman biraz temkinli davrandım INçünkü SQL Server'ın sonuç kümesini büyük bir IFifadeye dönüştürdüğüne inanıyorum . Büyük bir sonuç kümesi için bu, düşük performansa neden olabilir. Küçük sonuç kümeleri için ikisinin de tercih edilebilir olduğundan emin değilim. Büyük sonuç kümeleri EXISTSiçin daha verimli olmaz mıydı ?

WHERE EXISTS (SELECT * FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)

vs.

WHERE bx.BoxID IN (SELECT BoxID FROM Base WHERE [Rank = 2])

8
Bunu öğrenmenin en iyi yolu denemek ve bazı ölçümler yapmaktır.
Klaus Byskov Pedersen

10
olduğunumu var gelen milyarlarca bunun için çiftleri ...... olmak
Marc_s

5
@marc_s - Muhtemelen öyle, ama zamanla bu konudaki tüm yazılara bakmam ve durumuma uyan birini bulmam gerekiyordu, soruma dört cevabım vardı.
Randy Minder

7
Eğer isteyen konum Bilginize eğer en ölçülebilir şekilde yapabilirsiniz select 1 from Base...senin içinde where existsaslında sonuçları hakkında umurumda değil, çünkü bir satır gerçekte var sadece o.
brad

2
@marc_s bu gerçekten üzücü, çünkü stackoverflow'a daha fazla çöp eklememek için gönderilere bakmak için zaman ayırdım. İşimi bitirmek için özel bir cevaba ihtiyacım yok. Bu, iyi cevapları olan sadece birkaç
tanesinin yerine Gazillion

Yanıtlar:


140

EXISTS daha hızlı olacaktır çünkü motor bir isabet bulduğunda, durum doğru olduğu için aramayı bırakacaktır.

İle IN, daha fazla işlemden önce alt sorgudaki tüm sonuçları toplayacaktır.


4
İyi bir noktaya değindin. IN ifadesi, SQL Server'ın eksiksiz bir sonuç kümesi oluşturmasını ve ardından büyük bir IF ifadesi oluşturmasını gerektirir.
Randy Minder

72
Bu önceden doğruydu, ancak mevcut sürümlerde (en azından 2008) optimize edici çok daha akıllıdır ... aslında IN () 'yi bir EXISTS () gibi ele alır.
Aaron Bertrand

11
@Aaron - evet, genellikle iyileştirici dahili olarak daha iyi bir plan üretir. Ancak, dahili kısayollara güvenmek, daha karmaşık senaryolarda zararlı olabilir.
Scott Coates

2
Bu sadece yanlış. 2010 yılındaydı ve hala öyle.
Magnus

2
IN ve EXISTS tam olarak aynı sorgu planına ve GÇ'ye sahiptir. Performansta farklı olduklarını düşünmek için hiçbir sebep yok. zaman istatistiklerinizi kontrol edin ve kendinizi
hesaplayın

40

Kabul edilen cevap dar görüşlü ve soru biraz gevşek:

1) Solda, sağda veya her iki tarafta da bir örtme indeksinin mevcut olup olmadığını açıkça belirtmeyin.

2) Her ikisi de sol taraf setinin boyutunu ve sağ taraf setini giriş boyutunu hesaba katmaz.
(Soru sadece genel olarak büyük bir sonuç kümesinden bahsediyor ).

Optimize edicinin, (1) ve (2) nedeniyle önemli bir maliyet farkı olduğunda "içinde" ile "var" arasında dönüştürme yapacak kadar akıllı olduğuna inanıyorum, aksi takdirde yalnızca bir ipucu olarak kullanılabilir (ör. sağ tarafta aranabilir bir indeks).

Her iki form da dahili olarak birleştirme formlarına dönüştürülebilir, birleştirme sırası tersine çevrilebilir ve tahmini satır sayılarına (sol ve sağ) ve sol, sağ veya her iki taraftaki dizin varlığına bağlı olarak döngü, karma veya birleştirme olarak çalıştırılabilir.


3
bu mükemmel cevabın neden daha fazla dikkat çekmediğini bilmiyorum. Her iki taraf için endeksi / yapıyı anlamak, katılıyorum. İyi söyledin.
SheldonH

Optimiser hep aynı planı verir INve EXISTS. Aynı planı almadıkları herhangi bir durum bulmaya çalışın (bu NOT INve için geçerli olmasa da NOT EXISTS)
Martin Smith

@MartinSmith Neden bahsettiğinizi bildiğinizi varsayıyorum ama planların her zaman aynı olduğuna dair herhangi bir kanıtınız var mı? Öyleyse, buradaki on yıl süren anlaşmazlığı çözer.
MarredCheese

@MarredCheese - sorumluluk, bunun tek bir örneğini üretmenin farklı olduğunu iddia eden insanlarda
Martin Smith


5

Burada yüksek oy alan cevaplar da dahil olmak üzere birçok yanıltıcı cevap var (operasyonlarının zarar verdiğine inanmıyorum). Kısa cevap: Bunlar aynı.

(T-) SQL dilinde birçok anahtar sözcük vardır, ancak sonuçta, donanımda gerçekten gerçekleşen tek şey, yürütme sorgu planında görülen işlemlerdir.

Çağırdığımızda yaptığımız ilişkisel (matematik teorisi) işlem [NOT] INve [NOT] EXISTSyarı birleştirmedir (kullanırken birleşmeyi önleme NOT). Karşılık gelen sql-server işlemlerinin aynı ada sahip olması tesadüf değildir . Sadece (anti-) yarı birleşimlerden bahseden INveya EXISTSherhangi bir yerde işlem yoktur . Bu nedenle, mantıksal olarak eşdeğer INve EXISTSseçimin performansı etkilemesinin bir yolu yoktur, çünkü sonuçlarını almanın tek ve tek yolu (anti) yarı birleştirme yürütme işlemi vardır .

Bir örnek:

Sorgu 1 ( plan )

select * from dt where dt.customer in (select c.code from customer c where c.active=0)

Sorgu 2 ( plan )

select * from dt where exists (select 1 from customer c where c.code=dt.customer and c.active=0)

Test ettin mi? Öyleyse, SQL'inizi ve sonuçlarınızı paylaşabilir misiniz?
UnhandledExcepSean

Birden çok kez test etti. Başka bir test senaryosu oluşturabilirim ve yapacağım, ancak bir test senaryosu, optimize edicinin farklı istatistiklere sahip tablolarda aynı planı yapacağı anlamına gelmez. Bu, birisinin cevabın kısmi olduğunu düşünmesine yol açabilir - ancak birden fazla yarı birleştirme operatörünün olmaması gerçektir. Belki bir yerde bir liste bulur ve onu bağlarım.
George Menoutis

5

IN üzerinden EXISTS ile giderdim, aşağıdaki bağlantıya bakın:

SQL Server: JOIN - IN - EXISTS - mantıksal fark

Geri dönen sonuçlar açısından IN'in EXISTS veya JOIN'e eşit davrandığına dair yaygın bir yanlış kanı vardır. Bu kesinlikle doğru değil.

IN: Belirtilen bir değer, bir alt sorgu veya listedeki herhangi bir değerle eşleşirse doğru döndürür.

Var: Bir alt sorgu herhangi bir satır içeriyorsa doğru döndürür.

Birleştir: Birleştirme sütunundaki 2 sonuç kümesine katılır.

Blog kredisi: https://stackoverflow.com/users/31345/mladen-prajdic


Vay canına, blogunuz ve açıklamanız için teşekkür ederim.
Christian Müller

3

Bu durumlarda yürütme planları tipik olarak aynı olacaktır, ancak indekslerin diğer tüm yönlerinde optimize edici faktörlerin nasıl olduğunu görene kadar, gerçekten asla bilemezsiniz.


3

Yani IN, EXISTS ile aynı değildir ve aynı uygulama planını üretecektir.

EXISTS genellikle ilişkili bir alt sorguda kullanılır, bu da EXISTS iç sorgusunu dış sorgunuzla birleştireceğiniz anlamına gelir. Bu, dış sorgu birleşimlerini çözmeniz gerektiğinden ve iç sorgu birleştiğinden sonuç üretmek için daha fazla adım ekleyecek ve ardından her ikisini de birleştirmek için where cümlelerini eşleştirecektir.

Genellikle IN, iç sorguyu dış sorgu ile ilişkilendirmeden kullanılır ve bu yalnızca bir adımda çözülebilir (en iyi durum senaryosunda).

Bunu düşün:

  1. IN kullanırsanız ve iç sorgu sonucu milyonlarca farklı değer satırı ise, EXISTS sorgusunun yüksek performanslı olduğu (dış sorgu ile birleştirmek için doğru dizinlere sahip olduğu) göz önüne alındığında, muhtemelen EXISTS'den DAHA DAHA YÜKSEK performans gösterecektir.

  2. EXISTS kullanırsanız ve dış sorgunuzla birleştirme karmaşıksa (gerçekleştirilmesi daha fazla zaman alır, uygun dizin yok) dış tablodaki satır sayısına göre sorguyu yavaşlatır, bazen tamamlanması için tahmini süre gün cinsinden olabilir. Verilen donanımınız için satır sayısı kabul edilebilir düzeydeyse veya verilerin önem düzeyi doğruysa (örneğin, büyük bir veri kümesinde daha az DISTINCT değeri) IN, EXISTS'den daha hızlı performans gösterebilir.

  3. Yukarıdakilerin tümü, her bir tabloda makul miktarda satırınız olduğunda not edilecektir (adil olarak, CPU işlemlerinizi ve / veya önbelleğe alma için ram eşiklerinizi aşan bir şeyi kastediyorum).

Yani CEVAP BAĞIMLIDIR. IN veya EXISTS içinde karmaşık bir sorgu yazabilirsiniz, ancak genel bir kural olarak, çok sayıda farklı değere sahip çok sayıda satırınız olduğunda, sınırlı sayıda farklı değer ve EXISTS ile IN kullanmayı denemelisiniz.

İşin püf noktası, taranacak satır sayısını sınırlamaktır.

Saygılarımızla,

MarianoC


1

Optimize etmek için EXISTSçok basit olun; bir şeyin orada olması gerekir, ancak ilişkili alt sorgudan döndürülen herhangi bir veriye aslında ihtiyacınız yoktur. Sadece bir Boole koşulunu değerlendiriyorsunuz.

Yani:

WHERE EXISTS (SELECT TOP 1 1 FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)

İlişkili alt sorgu olduğu için RBAR, ilk sonuç isabeti koşulu doğru kılar ve daha fazla işlenmez.


LEFT JOIN + NULL kodlamasını kullanırken her zaman son derece dikkatli olurdum, çünkü NULL işleminizde çok dikkatli değilseniz, gözden kaçan veya çarpık sonuçlar almak çok kolaydır. Çok nadiren ikisini karşılamak aynı şartlar yapar, MEVCUT veya (tekrarlardan veya eksik veriler için sentetik ekleme bulmak için) bir CTE bir durum buldum ve + NULL KATILIN SOL daha iyi performans ettik
Josh Lewis

3
İLK 1, EXISTS ile kullanıldığında tamamen gereksiz (veya gereksiz olay) olmalıdır. EXISTS her zaman eşleşen bir satırı bulur bulmaz geri döner.
Karl Kieninger

Şimdiye kadar bu yaklaşımla herhangi bir performans avantajı görmedim. Lütfen Yürütme Planlarının bazı ekran görüntülerini gösterin
DaFi4

-1

Kafamın tepesinde ve doğru olduğu garanti edilmiyor: Bu durumda ikincinin daha hızlı olacağına inanıyorum.

  1. İlkinde, ilişkili alt sorgu muhtemelen her satır için alt sorgunun çalıştırılmasına neden olacaktır.
  2. İkinci örnekte, alt sorgu ilişkili olmadığı için yalnızca bir kez çalıştırılmalıdır.
  3. İkinci örnekte, INbir eşleşme bulur bulmaz kısa devre yapacaktır.
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.