SEÇENEK (TAVSİYE) endeksi SEEK kullanılmıyor mu?


11

(Soru SO'dan taşındı)

Kümelenmiş dizin 2 sütun içeren bir tablo (kukla veri) var:

resim açıklamasını buraya girin

Şimdi bu iki sorguyu çalıştırıyorum:

declare 
@productid int =1 , 
@priceid  int = 1




SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid OR @productid IS NULL)
       AND (priceid = @priceid OR @priceid IS NULL)  


SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid)
       AND (priceid = @priceid)

Her iki sorgu için gerçek yürütme planı:

resim açıklamasını buraya girin

Gördüğünüz gibi birincisi SCAN, ikincisi SEEK kullanıyor.

Ancak - OPTION (RECOMPILE)ilk sorguyu ekleyerek , yürütme planını da SEEK kullanmak için yaptı:

resim açıklamasını buraya girin

DBA sohbetindeki arkadaşlar bana şunları söyledi:

Sorgunuzda @ productid = 1, yani (productID = @ productID VEYA @ productIDID IS NULL) (productID = @ productID) ile basitleştirilebilir. Birincisi, herhangi bir @productID değeri ile çalışmak için bir tarama gerektirir, ikincisi bir arama kullanabilir. Bu nedenle, RECOMPILE kullandığınızda, SQL Server @productID'de gerçekte sahip olduğunuz değere bakar ve bunun için en iyi planı yapar. @ ProducttID değerinde null olmayan bir değerle, arama en iyisidir. @ProductID değeri bilinmiyorsa, planın @productID içindeki bir tarama gerektiren herhangi bir olası değere uyması gerekir. Dikkat edin: OPTION (RECOMPILE), her çalıştırdığınızda planı yeniden derlemeye zorlar ve bu da her yürütmeye birkaç milisaniye ekler. Sorgu çok sık çalışıyorsa bu sadece bir sorundur.

Ayrıca :

@ProductID boşsa, hangi değere bakarsınız? Cevap: aranacak bir şey yok. Tüm değerler geçerlidir.

Anlıyorum OPTION (RECOMPILE)SQL Server zorlar sahiptir değerleri parametreleri gerçek olduğunu görmek ve onunla ARAMA görmek için.

Ama şimdi ön derlemenin faydasını kaybediyorum.

Soru

IMHO - SCAN yalnızca bir parametre boşsa oluşur.
Bu iyi - SQL SERVER'ın SCAN için bir yürütme planı oluşturmasına izin verin.
AMA SQL Server, bu sorguyu birçok kez değerlerle çalıştırdığımı görürse: 1,1neden başka bir yürütme planı oluşturmuyor ve bunun için SEEK kullanmıyor?

AFAIK - SQL, en çok kullanılan sorgular için yürütme planı oluşturur .

  • SQL SERVER neden aşağıdakiler için bir yürütme planı kaydetmiyor:

    @productid int =1 , @priceid int = 1

(Bu değerlerle birçok kez çalıştırıyorum)

  • SQL'i gelecekteki çağrılar için yürütme planını (SEEK kullanan) tutmaya zorlamak mümkün mü?

Tam tablo komut dosyası + verileri oluşturma


Yanıtlar:


10

Sohbet odası tartışmamızdaki bazı temel noktaları özetlemek gerekirse :


Genel olarak, SQL Server her deyim için tek bir planı önbelleğe alır . Bu plan gelecekteki tüm olası parametre değerleri için geçerli olmalıdır .

Sorgunuz için bir arama planı önbelleğe almak mümkün değildir , çünkü örneğin, @productid boşsa bu plan geçerli olmaz .

Gelecekteki bazı sürümlerde, SQL Server, çalışma zamanı parametre değerlerine bağlı olarak bir tarama ve arama arasında dinamik olarak seçim yapan tek bir planı destekleyebilir, ancak bugün sahip olduğumuz bir şey değildir.

Genel problem sınıfı

Sorgunuz, "tümünü yakala" veya "dinamik arama" sorgusu olarak adlandırılan bir desene örnektir. Her birinin kendi avantajları ve dezavantajları olan çeşitli çözümler vardır. SQL Server'ın (2008+) modern sürümlerinde ana seçenekler şunlardır:

  • IF bloklar
  • OPTION (RECOMPILE)
  • Dinamik SQL kullanımı sp_executesql

Konuyla ilgili en kapsamlı çalışma, muhtemelen bu cevabın sonunda referanslara dahil edilen Erland Sommarskog'dur. İlgili karmaşıklıklardan kurtulmak mümkün değildir, bu nedenle her durumda ödünleşmeleri anlamak için her seçeneği denemek için biraz zaman ayırmak gerekir.

IF bloklar

Sorudaki IFözel durum için bir blok çözümü göstermek için:

IF @productid IS NOT NULL AND @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid
        AND T.priceID = @priceid;
END;
ELSE IF @productid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid;
END;
ELSE IF @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.priceID = @priceid;
END;
ELSE
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T;
END;

Bu, her iki parametrenin (veya yerel değişkenlerin) her biri için dört olası null veya null olmayan durum için ayrı bir ifade içerir, bu nedenle dört plan vardır.

Burada, OPTIMIZE FORher sorguda bir ipucu gerektirebilecek parametre koklama ile ilgili potansiyel bir sorun vardır . Bu tür incelikleri keşfetmek için lütfen referanslar bölümüne bakın.

recompile

Yukarıda belirtildiği gibi, soruda, OPTION (RECOMPILE)her bir çağrıda yeni bir plan (arama veya tarama) almak için bir ipucu da ekleyebilirsiniz . Durumunuzdaki görüşmelerin nispeten yavaş olması göz önüne alındığında (ortalama olarak her on saniyede bir, milisaniyenin altında bir derleme süresi ile), bu seçeneğin sizin için uygun olacağı düşünülmektedir:

SELECT
    T.productID,
    T.priceID
FROM dbo.Transactions AS T
WHERE
    (T.productID = @productid OR @productid IS NULL)
    AND (T.priceID = @priceid OR @priceid IS NULL)
OPTION (RECOMPILE);

Ayrıca, yukarıdaki seçeneklerden gelen özellikleri yaratıcı yollarla birleştirmek, her yöntemin avantajlarından en iyi şekilde yararlanmak ve olumsuz yanları en aza indirmek de mümkündür. Bu şeyleri ayrıntılı olarak anlamanın ve gerçekçi testlerle desteklenen bilinçli bir seçim yapmanın gerçekten bir kısayolu yoktur.

daha fazla okuma

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.