IF EXISTS'deki sorgulama çok yavaş yapıyor


16

Aşağıdaki sorgu var:

select databasename 
from somedb.dbo.bigtable l where databasename ='someval' and source  <>'kt'
and not exists(select 1 from dbo.smalltable c where c.source=l.source)

Yukarıdaki sorgu üç saniye içinde tamamlanır.

Yukarıdaki sorgu herhangi bir değer döndürürse, saklı yordamın EXIT olmasını istiyoruz, bu yüzden aşağıdaki gibi yeniden yazdım:

If Exists(
select databasename 
from somedb.dbo.bigtable l where databasename ='someval' and source  <>'kt'
and not exists(select 1 from dbo.smalltable c where c.source=l.source)
)
Begin
Raiserror('Source missing',16,1)
Return
End

Ancak bu 10 dakika sürüyor.

Yukarıdaki sorgu da 3 saniyeden daha kısa sürede tamamlanır aşağıdaki gibi yeniden yazabilirsiniz:

  select databasename 
from somedb.dbo.bigtable l where databasename ='someval' and source  <>'kt'
and not exists(select 1 from dbo.smalltable c where c.source=l.source
if @@rowcount >0
Begin
Raiserror('Source missing',16,1)
Return
End

Yukarıdaki yeniden yazmayla ilgili sorun, yukarıdaki sorgunun daha büyük saklı yordamın bir parçası olması ve birden çok sonuç kümesi döndürmesidir. C # 'da, her sonuç kümesi boyunca yineleme yaparız ve bazı işlemler yaparız.

Yukarıdaki boş bir sonuç kümesi döndürür, bu yüzden bu yaklaşım ile gitmek, C # değiştirmek ve yeniden dağıtım yapmak zorunda.

Benim sorum şu,

Neden kullanmak IF EXISTSbu kadar zaman alacak planı değiştiriyor?

Aşağıda size yardımcı olabilecek ayrıntılar ve herhangi bir ayrıntıya ihtiyacınız varsa bana bildirin:

  1. Benimkiyle aynı planı almak için tablo ve istatistik komut dosyası oluştur
  2. Yavaş İcra Planı
  3. Hızlı Uygulama Planı

    Brentozar kullanarak yavaş plan planı Yapıştır Brentozar kullanarak
    hızlı plan planı Yapıştır

Not: Her iki sorgu da aynıdır (parametreleri kullanarak), tek fark EXISTS(anonimleştirirken bazı hatalar yapmış olabilirim).

Tablo oluşturma komut dosyaları aşağıdadır:

http://pastebin.com/CgSHeqXc - küçük masa istatistikleri
http://pastebin.com/GUu9KfpS - büyük masa istatistikleri


Yanıtlar:


18

Paul White tarafından blog yazısında açıklandığı gibi : Optimizer İçinde: Satır Hedefleri Derinlemesine , EXISTSbir NESTED LOOPSveya daha MERGE JOINfazla tercih eden bir satır hedefi sunarHASH MATCH

Son bir örnek olarak, mantıksal bir yarı birleştirmenin (EXISTS ile sunulan bir alt sorgu gibi) genel temayı paylaştığını düşünün: ilk eşleşen satırı hızlı bir şekilde bulmak için optimize edilmelidir.

Sorgunuzda bu, iç içe geçmiş döngüler tanıtmak ve paralelliğin kaldırılmasıyla ortaya çıkıyor ve bu da daha yavaş bir planla sonuçlanıyor.

Bu nedenle, sorgunuzdaki sorgusunu kullanmadan sorgunuzu yeniden yazmanın bir yolunu bulmanız gerekir NOT EXISTS.

LEFT OUTER JOINA'yı kullanarak sorgunuzu yeniden yazmaktan ve test ederek smalltable'da bir satır bulunmadığından emin olabilirsiniz.NULL

If EXISTS(
    SELECT databasename
    FROM somedb.dbo.bigtable l
    LEFT JOIN dbo.smalltable c ON c.source = l.source
    WHERE databasename = 'someval'
    AND source <> 'kt'
    AND c.source IS NULL
)

Şu EXCEPTşekilde karşılaştırmanız gereken alan sayısına bağlı olarak, muhtemelen bir sorgu da kullanabilirsiniz :

If EXISTS(
   SELECT source
   FROM somedb.dbo.bigtable l
   WHERE databasename = 'someval'
   AND source <> 'kt'

   EXCEPT

   SELECT source
   FROM dbo.smalltable
)

Bak, Aaron Bertrand bir blog yazısı vardır o DEĞİL tercih MEVCUT nedenlerini sağlayan diğer yaklaşımlar iyi olup olmadığını görün üzerine okumalı ve NULL değerler söz konusu olduğunda potansiyel doğruluğu sorunların farkında olmak hangi.

İlgili Soru-Cevap: EXISTS, gömülü select deyiminden daha uzun sürüyorsa


0

Sorgunuzu açık birleştirmeler kullanarak yeniden yazmanız ve bunun gibi hangi birleştirme işlemini (döngü, karma veya birleştirme) kullanmak istediğinizi belirtmeniz gerekir.

If not exists(
    select databasename 
    from somedb.dbo.bigtable l
    inner hash join dbo.smalltable c 
        on c.source = l.source
where databasename ='someval' and source  <>'kt')
begin
    Raiserror('Source missing',16,1)
    Return
end

EXISTS veya NOT EXISTS kullanırken, koşulu yerine getirmek için ilk satırı arayan kümedeki tüm satırları tek tek geçmesi gerektiğini varsayarak SQL Server tarafından oluşturulan sorgu planı NESTED LOOP işlemiyle. HASH JOIN kullanımı hızlandıracaktır.


Sizden, test
edeceksiniz

0

Ben de aynı sorunla karşılaştım, "EXISTS" kullanmaktan kaçınarak ve "COUNT ()" işlevini ve "IF ... ELSE" deyimini kullanarak kendimi çalışmayı başardım.

Örneğiniz için aşağıdakileri deneyin:

IF
(
    SELECT
        COUNT(l.databasename) + 1 AS databasename
    FROM somedb.dbo.bigtable AS l

    WHERE   l.databasename ='someval'
        AND l.[source]  <> 'kt'
        AND NOT EXISTS(SELECT 1 FROM dbo.smalltable AS c WHERE c.[source]=l.[source])
) > 1 --Acts like EXISTS
BEGIN
    RAISERROR('Source missing', 16, 1)
RETURN
END

Saymaya "+ 1" eklememin nedeni, "> 0" veya "<> 0" kullanıldığında sorguyu HASH yerine iç içe döngüler kullanması için tetikleyecek şekilde "> 1" komutunu kullanabilmemdir. Eşleşme. Bunun tam olarak neden olduğunu anlamak için nedenini bulmak ilginç olurdu.

Umarım yardımcı olur!

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.