OPTION (TAVSİYE) Daima Daha Hızlı; Neden?


169

Sorguma ekleme OPTION (RECOMPILE), sorgunun beş dakikadan fazla sürmesine neden olurken, sorguma ekleme yarım saniye içinde çalışmasına neden olduğu garip bir durumla karşılaştım .

Sorgu Query Analyzer'dan veya C # programım üzerinden yürütüldüğünde durum budur SqlCommand.ExecuteReader(). Aramak (veya aramamak) DBCC FREEPROCCACHEveya DBCC dropcleanbuffersfark etmez; Sorgu sonuçları her zaman anında OPTION (RECOMPILE)ve olmadan beş dakikadan daha uzun süre döndürülür . Sorgu her zaman aynı parametrelerle [bu test uğruna] çağrılır.

SQL Server 2008 kullanıyorum.

SQL yazma konusunda oldukça rahatım, ancak daha OPTIONönce bir sorguda bir komut kullanmadım ve bu forumdaki mesajları tarayana kadar plan önbelleklerinin tüm konseptine aşina değildim . Görevlerden aldığım anlayış OPTION (RECOMPILE)pahalı bir operasyon. Görünüşe göre sorgu için yeni bir arama stratejisi oluşturuyor. Öyleyse neden, atlayan sonraki sorgular bu OPTION (RECOMPILE)kadar yavaş? Sonraki sorgular, yeniden derleme ipucunu içeren önceki çağrıda hesaplanan arama stratejisini kullanmıyor mu?

Her aramada yeniden derleme ipucu gerektiren bir sorguya sahip olmak son derece sıra dışı mı?

Giriş seviyesi soru için özür dilerim ama bununla ilgili kafa ya da kuyruk yapamıyorum

GÜNCELLEME: Sorguyu göndermem istendi ...

select acctNo,min(date) earliestDate 
from( 
    select acctNo,tradeDate as date 
    from datafeed_trans 
    where feedid=@feedID and feedDate=@feedDate 

    union 

    select acctNo,feedDate as date 
    from datafeed_money 
    where feedid=@feedID and feedDate=@feedDate 

    union 

    select acctNo,feedDate as date 
    from datafeed_jnl 
    where feedid=@feedID and feedDate=@feedDate 
)t1 
group by t1.acctNo
OPTION(RECOMPILE)

Testi Query Analyzer'dan çalıştırırken aşağıdaki satırların başına ekliyorum:

declare @feedID int
select @feedID=20

declare @feedDate datetime
select @feedDate='1/2/2009'

Benim C # programından çağırırken, parametreleri SqlCommand.Parametersözellik üzerinden geçirilir .

Bu tartışmanın amaçları doğrultusunda, parametrelerin asla değişmediğini varsayabiliriz, bu nedenle neden olarak optimal olmayan parametre kokusunu ekarte edebiliriz.


3
Sorguya ilişkin parametreler nelerdir? Bu makaleye göz atın. blogs.msdn.com/b/turgays/archive/2013/09/10/… Temel olarak SQL, proc ilk derlendiğinde parametrelere dayalı olarak sorgu planı oluşturmaya çalışır. Farklı, muhtemelen daha gerçekçi parametreler geçmeye başladığınızda en uygun olmayan bir plan oluşturabilir
Sparky

3
Sorgu burada listelenecek kadar kısa mı? Sparky'nin doğru olduğunu ve muhtemelen parametre koklamasıyla ilgili olduğunu düşünüyorum, bu mükemmel makaleyi okuyana
Chris

1
Ama bu durumda (bu test uğruna) her zaman aynı parametreleri geçiyorum. Başka hiçbir uygulama gizlice girip sorguyu diğer parametreleri kullanarak çağıramadı. Makaleler için teşekkürler. Gözden geçirecek.
Chad Decker

2
Bu, parametrelerin ve değişkenlerin değerlerini koklaması veya daha fazla basitleştirme yapması nedeniyle olabilir. Büyük basitleştirmelerin örnekleri çöken olacağını X = @X OR @X IS NULLetmek X=@Xve bir aramaya performans Burada See veya pencere fonksiyonları ile bir görünümde karşı daha aşağı yüklemler iterek
Martin Smith

3
Düzenlemenizi takiben, Query Analyzer örneği parametreleri değil değişkenleri kullanır. Bunların değeri dışında hiçbir zaman koklanmaz RECOMPILE. Her durumda yürütme planlarını yakalayın ve farklılıklara bakın.
Martin Smith

Yanıtlar:


157

Kullanmanın OPTION(RECOMPILE)mantıklı olduğu zamanlar vardır . Benim deneyimime göre bu, dinamik SQL kullandığınızda geçerli bir seçenektir. Durumunuzda bunun mantıklı olup olmadığını keşfetmeden önce istatistiklerinizi yeniden oluşturmanızı tavsiye ederim. Bu, aşağıdakileri çalıştırarak yapılabilir:

EXEC sp_updatestats

Ve sonra yürütme planınızı yeniden oluşturun. Bu, yürütme planınız oluşturulduğunda en son bilgileri kullanmasını sağlayacaktır.

Ekleme OPTION(RECOMPILE), sorgunuz her çalıştırıldığında yürütme planını yeniden oluşturur. Bunu tarif creates a new lookup strategyettiğimi hiç duymadım ama belki de aynı şey için farklı terimler kullanıyoruz.

Saklı yordam oluşturulduğunda (.NET'ten ad-hoc sql çağırdığından şüpheleniyorum, ancak parametreli bir sorgu kullanıyorsanız, o zaman bu depolanmış bir proc çağrısı olur ) SQL Server bu sorgu için en etkili yürütme planını belirlemeye çalışır veritabanınızdaki verilere ve geçirilen parametrelere ( parametre koklama ) bağlı olarak bu planı önbelleğe alır. Bu, veritabanınızda 10 kaydın bulunduğu sorguyu oluşturup 100.000.000 kayıt olduğunda yürüttüğünüzde önbelleğe alınmış yürütme planının artık en etkili olmayacağı anlamına gelir.

Özetle - OPTION(RECOMPILE)Burada yarar sağlayacak herhangi bir neden göremiyorum . İstatistiklerinizi ve yürütme planınızı güncellemeniz gerektiğinden şüpheleniyorum. İstatistikleri yeniden oluşturmak, durumunuza bağlı olarak DBA çalışmasının önemli bir parçası olabilir. İstatistiklerinizi güncelledikten sonra hala sorun yaşıyorsanız, her iki yürütme planını da göndermenizi öneririm.

Ve sorunuzu cevaplamak için - evet, sorguyu her yürüttüğünüzde en iyi seçeneğinizin yürütme planını yeniden derlemenin oldukça sıra dışı olduğunu söyleyebilirim.


22
Evet, sp_updatestats hile yaptı. Başlangıçta 10 kayıtlı bir tablo üzerinde çalışan bir sorgudan bahsettiğinizde kafasına çiviyi vurdunuz ve şimdi tablonun milyonlarca kaydı var. Benim durumum buydu. Mesajda bahsetmedim çünkü önemli olduğunu düşünmedim. Büyüleyici şeyler. Tekrar teşekkürler.
Chad Decker

3
Tablo değişkenleriyle çalışmayı bulduğum tek yol, SQL her zaman tek bir satır olduğunu düşünüyor. Binlerce satır içerdiğinde sorun oluyor.
Alex Zhukovskiy

4
İlginç bir ayrıntı: istatistiklerin güncellenmesi, bu istatistikleri kullanan tüm önbelleğe alınan planları örtülü olarak geçersiz kılar, ancak istatistikler yalnızca güncelleme işleminden sonra gerçekten değiştiğinde . Bu nedenle, yüksek oranda eğrilmiş salt okunur tablolar OPTION (RECOMPILE)için tek çözüm açık olabilir.
Groo

141

Genellikle bir sorgu çalışma çalıştırmak için büyük bir fark olduğunda genellikle 5 sorunlarından biri olduğunu bulmak.

  1. İSTATİSTİK- İstatistikler güncel değil. Bir veritabanı, tablo ve dizinlerdeki çeşitli sütundaki değer türlerinin aralığı ve dağılımı hakkındaki istatistikleri depolar. Bu, sorgu motorunun sorguyu nasıl yapacağına ilişkin bir "Plan" saldırı geliştirmesine yardımcı olur, örneğin bir karma kullanarak veya tüm kümeye bakarak tablolar arasındaki anahtarları eşleştirmek için kullanacağı yöntem türü. Tüm veritabanında veya yalnızca belirli tablolarda veya dizinlerde Güncelleme İstatistikleri'ni çağırabilirsiniz. İstatistikler güncel olmadığında, sorgu planının aynı sorgu için yeni eklenen veya değiştirilen veriler için uygun olmaması muhtemel olduğundan (bu, aşağıda daha sonra açıklanacaktır) bu, sorguyu bir çalıştırmadan diğerine yavaşlatır. Örnekleme yapılacak veri miktarına bağlı olarak bazı ek yük, yavaşlama ve gecikmeler olacağından, Üretim veritabanında İstatistikleri hemen güncellemek uygun olmayabilir. İstatistikleri güncellemek için Tam Tarama veya Örnekleme kullanmayı da seçebilirsiniz. Sorgu Planına bakarsanız, bu durumda kullanılan Dizinlerdeki istatistikleri şu komutu kullanarak da görüntüleyebilirsiniz:DBCC SHOW_STATISTICS (tablename, indexname) . Bu, sorgu planının yaklaşımını temel almak için kullandığı anahtarların dağılımını ve aralıklarını gösterir.

  2. PARAMETRE SNIFFING - Önbelleğe alınan sorgu planı, sorgunun kendisi değişmese bile, geçtiğiniz belirli parametreler için uygun değildir. Örneğin, 1.000.000 satırdan yalnızca 10'unu alan bir parametreyi iletirseniz, oluşturulan sorgu planı Karma Birleştirme kullanabilir, ancak ilettiğiniz parametre 1.000.000 satırın 750.000'ini kullanacaksa, oluşturulan plan bir dizin taraması veya tablo taraması. Böyle bir durumda SQL deyimine OPTION (RECOMPILE) seçeneğini veya SP'yi RECOMPILE ile kullanmak için kullanabilirsiniz. Motora bunun bir "Tek Kullanımlık Plan" olduğunu söylemek ve büyük olasılıkla geçerli olmayan bir Önbellek Planı kullanmak değil. Bu kararın nasıl alınacağına dair bir kural yoktur, sorgunun kullanıcılar tarafından nasıl kullanılacağını bilmek bağlıdır.

  3. DİZİNLER - Sorgunun değişmemiş olması mümkündür, ancak çok kullanışlı bir dizinin kaldırılması gibi başka bir değişiklik sorguyu yavaşlatmıştır.

  4. ROWS CHANGED - Sorguladığınız satırlar çağrıdan çağrıya büyük ölçüde değişir. Genellikle bu durumlarda istatistikler otomatik olarak güncellenir. Ancak, dinamik SQL oluşturuyorsanız veya SQL'i sıkı bir döngü içinde çağırıyorsanız, yanlış köklü sayıda satıra veya istatistiğe dayalı olarak eski bir Sorgu Planı kullanma olasılığı vardır. Yine bu durumda SEÇENEK (TAVSİYE) kullanışlıdır.

  5. MANTIK Mantık, sorgunuz artık verimli değil, az sayıda satır için iyi, ancak artık ölçeklenmiyor. Bu genellikle Sorgu Planının daha ayrıntılı analizini içerir. Örneğin, artık işleri toplu olarak yapamazsınız, ancak işleri yığınlamak ve daha küçük Taahhütler yapmak zorunda kalırsınız veya Çapraz Ürününüz daha küçük bir set için iyidir, ancak artık daha büyük ölçeklendikçe CPU ve Belleği kaplıyor, bu da doğru olabilir DISTINCT kullanarak, her satır için bir işlev çağırıyorsunuz, anahtar eşleşmeleriniz DÖKÜM türü dönüşümü veya NULLS veya işlevler nedeniyle bir dizin kullanmıyor ... Burada çok fazla olasılık var.

Genel olarak bir sorgu yazarken, bazı verilerin tablonuzda nasıl dağıtıldığına dair zihinsel bir resminiz olmalıdır. Örneğin, bir sütun eşit olarak dağıtılmış sayıda farklı değere sahip olabilir veya eğrilebilir, zamanın% 80'i, dağıtımın zaman içinde sık sık değişip değişmeyeceği veya oldukça statik olup olmadığı zamanın belirli bir değer kümesine sahiptir. Bu, verimli bir sorgu oluşturma konusunda size daha iyi bir fikir verecektir. Ancak, sorgu performansında hata ayıklarken, neden yavaş veya verimsiz olduğuna dair bir hipotez oluşturmak için bir temel oluşturur.


2
teşekkürler arkadaşım. Bu mükemmel bir bilgidir. Sorumu ilk olarak gönderdiğimde cevabınızı anlayamazdım ama şimdi bana çok mantıklı geliyor.
Chad Decker

3
PARAMETRE SNIFFING benim varlığımın en büyük sorunudur. Başarısız bir röportaj sorusuna kadar bu komutu bile bilmiyordum. Parametre koklama çözümüm her zaman parametre değerlerini hash etmek ve "AND {hash} = {hash}" ekini eklemekti, böylece sql her zaman farklı değerler için farklıydı. Kesmek, ama işe yaradı.
Jeremy Boyd

27

OPTION (RECOMPILE) öğesinin çok yardımcı olabileceği durumların (@CodeCowboyOrg tarafından verilen) mükemmel listesine eklemek için,

  1. Tablo Değişkenleri . Tablo değişkenlerini kullanırken, tablo değişkeni için önceden oluşturulmuş istatistikler olmayacak ve genellikle sorgu planında tahmini ve gerçek satırlar arasında büyük farklılıklara yol açacaktır. Tablo değişkenlerine sahip sorgular üzerinde OPTION (RECOMPILE) kullanmak, ilgili satır numaralarını çok daha iyi tahmin eden bir sorgu planının oluşturulmasına olanak tanır. OPTION (RECOMPILE) eklenene kadar kullanılamayan ve terk edeceğim bir tablo değişkeninin özellikle kritik bir kullanımı vardı. Çalışma süresi saatlerden birkaç dakikaya indi. Bu muhtemelen olağandışıdır, ancak her durumda, tablo değişkenlerini kullanıyorsanız ve optimizasyon üzerinde çalışıyorsanız, OPTION (RECOMPILE) öğesinin bir fark yaratıp yaratmadığını görmeye değer.

1
5 tablo değişkenleri ile bir sorgu var. Makinemde yarım saatten fazla çalışıyor. İş arkadaşımın makinesinde <1 saniye içinde çalışıyor. Makineler benzer donanıma ve aynı SQL Server sürümüne sahiptir. Eğer ikimiz de OPTION (RECOMPILE) eklersek, her iki makinede de 2 saniye içinde çalışır. Her durumda, yürütme testi SSMS'de gerçekleştirilir. Bu farklılığa ne sebep olabilir?
Adam

1
Bunun için yürütme planını Seçenek (yeniden derleme) olmadan makinenizde ve iş arkadaşlarınızın makinesinde karşılaştırabilir misiniz? Bu farkın kaynağını gösterebilir.
DWar

1
geçici tablolar için de aynı durum geçerli mi?
Muflix

1
@muflix: güzel soru. Geçici tablolar için etkinin aynı olduğuna inanmıyorum, çünkü istatistikleri var ve motor diğer tablolar gibi otomatik yeniden derleme seçimleri yapıyor olmalı, inanıyorum (ama emin değilim). Belki başka biri daha kesin olarak bilir.
DWright

2
Geçici tablolardaki istatistikler otomatik olarak güncellenmez veya yeniden derlenmez, bu nedenle programcının bunu yapması gerekir.
J. Michael Wuerth

1

Sorguları düzeltmeden önceki ilk işlemler, dizinleri ve istatistikleri birleştirmek / yeniden oluşturmaktır, aksi takdirde zamanınızı boşa harcıyorsunuz.

İstikrar olup olmadığını görmek için yürütme planını kontrol etmelisiniz (parametreleri değiştirdiğinizde aynıdır), eğer değilse, bir kapak dizini (bu durumda her tablo için) oluşturmanız gerekebilir (bu sistemi bir diğer sorgular için de yararlıdır).

örnek olarak: idx01_datafeed_trans dizinini oluştur datafeed_trans (feedid, feedDate) üzerinde INCLUDE (acctNo, tradeDate)

plan kararlıysa veya stabilize edebiliyorsanız, sabit bir yürütme planını kaydetmek ve kullanmak için cümleyi sp_executesql ('sql cümlesi') ile yürütebilirsiniz.

plan kararsızsa, her seferinde bir yürütme planı değerlendirmek ve oluşturmak için geçici bir ifade veya EXEC ('sql cümlesi') kullanmanız gerekir. (veya "yeniden derleme ile" saklı bir yordam).

Umarım yardımcı olur.


1

Bu soruyu küçümsemek ama kimsenin dikkate almadığı bir açıklama var.

İSTATİSTİK - İstatistikler mevcut değil veya yanıltıcı

Aşağıdakilerin tümü doğruysa:

  1. Feedid ve feedDate sütunlarının büyük oranda ilişkilendirilmesi muhtemeldir (örneğin, bir feed kimliği bir feed tarihinden daha spesifiktir ve date parametresi gereksiz bilgilerdir).
  2. Her iki sütunu da sıralı sütun olarak içeren bir dizin yoktur.
  3. Bu sütunların her ikisini de kapsayan manuel olarak oluşturulmuş istatistikler yoktur.

Daha sonra sql sunucusu, sütunların birbiriyle ilişkili olmadığını varsayarak, hem kısıtlamaları hem de kötü bir yürütme planının seçilmesi için beklenenden daha düşük kardinalite tahminlerine yol açabilir. Bu durumda düzeltme, pahalı bir işlem olmayan iki sütunu bağlayan bir istatistik nesnesi oluşturmak olacaktı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.