Parametre Sniffing vs VARIABLES vs Recompile vs OPTIMIZE FOR UNKNOWN


40

Bu yüzden bu sabah sorunlara neden olan uzun bir proc vardı (30 sn + çalışma süresi). Parametre koklamanın suçlu olup olmadığını kontrol etmeye karar verdik. Böylece, proc'u yeniden yazdık ve gelen parametreleri parametrelerin koklamasını engellemek için değişkenlere ayarladık. Denenmiş / gerçek bir yaklaşım. Bam, sorgu süresi düzeldi (1 saniyeden az). Sorgu planına bakıldığında, iyileştirmeler orijinalin kullanmadığı bir dizinde bulundu.

Yanlış bir pozitif olmadığımızı doğrulamak için, orijinal proc üzerinde bir dbcc freeproccache yaptık ve iyileştirilmiş sonuçların aynı olup olmadığını görmek için reran'ı denedik. Ancak, sürprizimiz için orjinal süreç hala yavaşladı. Yine bir RECOMPILE ile denedim, yine de yavaş (proc ve proc'un çağrısında bir derleme yaptık). Hatta sunucuyu yeniden başlattık (açıkçası dev kutusu).

Öyleyse sorum şu: boş bir plan önbellekte aynı yavaş sorguyu aldığımızda, koklama parametresi nasıl suçlanabilir? ... koklayacak herhangi bir parametre olmamalı mı ???

Bunun yerine, plan önbellekle ilgili olmayan tablo istatistiklerinden etkileniyor muyuz? Ve eğer öyleyse, neden gelen parametreleri değişkenlere ayarlamak neden yardımcı olur?

Daha ileri testlerde, OPD (OPTIMIZE FOR UNKNOWN) proc DID'nin içindekilerine yerleştirilmesinin beklenen iyileştirilmiş planı aldığını gördük .

Öyleyse, bazılarınız benden daha akıllı, bu tür bir sonuç elde etmek için sahne arkasında neler olup bittiği hakkında ipucu verebilir misiniz?

Başka bir notta, yavaş plan aynı zamanda erken sebeple iptal GoodEnoughPlanFoundedilirken, hızlı planın fiili plandaki erken iptal sebebi yoktur.

Özetle

  • Gelen parametrelerden değişken oluşturma (1 sn)
  • yeniden derleme ile (30+ sn)
  • dbcc freeproccache (30+ saniye)
  • SEÇENEK (İNGİLTERE İÇİN OPTİMİZASYON) (1 sn)

GÜNCELLEME:

Burada yavaş yürütme planına bakın: https://www.dropbox.com/s/cmx2lrsea8q8mr6/plan_slow.xml

Burada hızlı uygulama planına bakınız: https://www.dropbox.com/s/b28x6a01w7dxsed/plan_fast.xml

Not: tablo, şema, nesne isimleri güvenlik nedenleriyle değiştirildi.

Yanıtlar:


43

Sorgu

SELECT SUM(Amount) AS SummaryTotal
FROM   PDetail WITH(NOLOCK)
WHERE  ClientID = @merchid
       AND PostedDate BETWEEN @datebegin AND @dateend 

Tablo 103.129.000 satır içeriyor.

Hızlı plan, ClientId tarafından tarihte artık bir tahminde bulunur, ancak almak için 96 arama yapılması gerekir Amount. <ParameterList>Şöyle planında bölümdür.

        <ParameterList>
          <ColumnReference Column="@dateend" 
                           ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
          <ColumnReference Column="@datebegin" 
                           ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
          <ColumnReference Column="@merchid" 
                           ParameterRuntimeValue="(78155)" />
        </ParameterList>

Yavaş plan tarihe göre bakar ve İstemci Kimliği üzerindeki kalıntı yüklemeyi değerlendirmek ve tutarı almak için arama yapar (Tahmini 1 - Gerçek 7,388,383). <ParameterList>bölümdür

        <ParameterList>
          <ColumnReference Column="@EndDate" 
                           ParameterCompiledValue="'2013-02-01 23:59:00.000'" 
                           ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
          <ColumnReference Column="@BeginDate" 
                           ParameterCompiledValue="'2013-01-01 00:00:00.000'"               
                           ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
          <ColumnReference Column="@ClientID" 
                           ParameterCompiledValue="(78155)" 
                           ParameterRuntimeValue="(78155)" />
        </ParameterList>

Bu ikinci durumda ParameterCompiledValueise değil boş. SQL Server, sorguda kullanılan değerleri başarıyla kokladı.

"SQL Server 2005 Pratik Sorun Giderme" kitabında yerel değişkenlerin kullanımı hakkında söylenecek söz var.

Parametre koklamayı engellemek için yerel değişkenleri kullanmak oldukça yaygın bir hiledir, ancak OPTION (RECOMPILE)ve OPTION (OPTIMIZE FOR)ipuçları… genellikle daha zarif ve biraz daha az riskli çözümlerdir.


Not

SQL Server 2005'te, ifade seviyesi derlemesi, sorgunun ilk yürütülmesinden hemen öncesine kadar ertelenecek olan saklı yordamdaki tek bir ifadenin derlenmesine izin verir. O zamana kadar yerel değişkenin değeri bilinirdi. Teorik olarak SQL Server, yerel değişken değerlerini parametreleri koklamakla aynı şekilde çekmek için bundan yararlanabilir. Ancak, SQL Server 7.0 ve SQL Server 2000+ 'de parametre koklama özelliğini engellemek için yerel değişkenlerin kullanılması yaygın olduğundan, yerel değişkenlerin koklaması SQL Server 2005'te etkinleştirilmemiştir. Gelecekteki bir SQL Server sürümünde etkin olabilir. Bir seçeneğiniz varsa, bu bölümde belirtilen diğer seçeneklerden birini kullanmanızın nedeni.


Hızlı bir testten bu sona kadar yukarıda açıklanan davranış hala 2008 ve 2012'de aynıdır ve ertelenmiş derlemeler için değişkenler koklanmamaktadır, ancak sadece açık bir OPTION RECOMPILEipucu kullanıldığında.

DECLARE @N INT = 0

CREATE TABLE #T ( I INT );

/*Reference to #T means this statement is subject to deferred compile*/
SELECT *
FROM   master..spt_values
WHERE  number = @N
       AND EXISTS(SELECT COUNT(*) FROM #T)

SELECT *
FROM   master..spt_values
WHERE  number = @N
OPTION (RECOMPILE)

DROP TABLE #T 

Ertelenmiş derlemeye rağmen, değişken koklamaz ve tahmini satır sayısı yanlış

Tahminler vs Gerçek

Dolayısıyla yavaş planın, sorgunun parametrelenmiş bir versiyonuyla ilgili olduğunu varsayıyorum.

Bu ParameterCompiledValue, ParameterRuntimeValuetüm parametrelere eşittir, bu nedenle tipik bir parametre koklama değildir (plan bir değer kümesi için derlenmiştir, sonra başka bir değer kümesi için çalıştırılır).

Sorun, doğru parametre değerleri için derlenen planın uygunsuz olmasıdır.

Burada ve burada açıklanan yükselen tarihlerle konuya ulaşmanız muhtemeldir . 100 milyon satırlık bir tablo için, SQL Server'ın istatistikleri sizin için otomatik olarak güncellemesinden önce 20 milyonu eklemeniz (veya başka şekilde değiştirmeniz) gerekir. Görünüşe göre, en son sıfır satır güncellendiğinde, sorgudaki tarih aralığıyla eşleşti ancak şimdi 7 milyon kişi var.

Daha sık istatistik güncellemeleri planlayabilir, izleme bayraklarını göz önünde bulundurabilir 2389 - 90veya kullanabilirsiniz; OPTIMIZE FOR UKNOWNböylece, datetimesütunda şu anda yanıltıcı istatistikleri kullanabilmek yerine, tahminlerde geri dönersiniz .

Bu, SQL Server'ın bir sonraki sürümünde gerekli olmayabilir (2012'den sonra). Bir ilişkili Bağlan öğesi ilginç yanıtını içeren

Microsoft tarafından 28.08.2012 tarihinde saat 13: 35'de gönderildi.
Bir sonraki önemli sürüm için bu durumu düzelten bir önemlilik tahmini geliştirmesi yaptık. Önizlememiz çıktığında ayrıntılar için bizi izlemeye devam edin. Eric

Bu 2014 gelişimine, makalenin sonuna doğru Benjamin Nevarez tarafından bakıldı:

Yeni SQL Server Kardinalite Tahmincisine İlk Bakış .

Yeni kardinalite tahmincisinin geri çekileceği ve bu durumda 1 satır tahminini vermek yerine ortalama yoğunluğu kullanacağı görülüyor.

2014 kardinalite tahmincisi ve artan anahtar sorun hakkında bazı ek ayrıntılar burada:

SQL Server 2014'te yeni işlevler - Bölüm 2 - Yeni Kardinalite Tahmini


29

Öyleyse sorum şu: boş bir plan önbellekte aynı yavaş sorguyu aldığımızda parametre koklama nasıl suçlanabilir? ... koklayacak herhangi bir parametre olmamalı mı?

SQL Server, parametre değerleri içeren bir sorgu oluşturduğunda, kardinalite (satır sayısı) tahmini için bu parametrelerin belirli değerlerini koklar . Senin durumunda, belirli değerleri @BeginDate, @EndDateve @ClientIDyürütme planı seçerken kullanılır. Burada ve burada parametre koklama hakkında daha fazla ayrıntı bulabilirsiniz . Bu arka plan bağlantılarını sağlıyorum çünkü yukarıdaki soru, kavramın şu anda kusurlu bir şekilde anlaşıldığını düşünmeme neden oluyor - bir plan derlenirken daima burnunu çekmek için parametre değerleri vardır.

Her neyse, mesele bunun dışında, çünkü parametre koklama Martin Smith'in işaret ettiği gibi sorun değil. Yavaş sorgu derlendiğinde, istatistiklerin sniffed değerleri için hiçbir satır olmadığı belirtildi @BeginDateve @EndDate:

Yavaş plan koklama değerleri

Koklanan değerler çok yakın bir zamanda, Martin'in belirttiği önemli kilit problemi ortaya koyuyor. Tarihlerdeki endeks aramasının yalnızca tek bir satır döndüreceği tahmin edildiğinden optimizer, yüklemeyi ClientIDKey Lookup operatörüne artık olarak kaldıran bir plan seçer .

Tek satır tahmini de, optimizer'ın İyi Yeterince Plan Bulundu mesajı döndürerek daha iyi planlar aramayı bırakmasının nedenidir. Tek satırlı tahmini ile yavaş planın tahmini toplam maliyeti sadece 0.013136 maliyet birimidir, bu nedenle daha iyi bir şey bulmaya çalışmanın bir anlamı yoktur. Tabii ki, arayış, gerçekte, aynı sayıda Anahtar Aramaya neden olan 7.388.383 satır döndürüyor.

İstatistikler, büyük tablolarda güncel kalmak için yararlı olabilir ve bölümleme , bu konuda kendi zorluklarını ortaya çıkarır. 2389 ve 2390 iz bayraklarıyla kendime özel bir başarı elde etmedim, ancak bunları test etmenizi bekliyoruz. SQL Server'ın (R2 SP1 ve üstü) daha yeni sürümlerinde kullanılabilen dinamik istatistik güncellemeleri var, ancak bu bölüm başına istatistik güncellemeleri hala uygulanmıyor. Bu arada, bu tabloda önemli değişiklikler yaptığınızda manuel bir istatistik güncellemesi planlamak isteyebilirsiniz.

Bu özel sorgu için, hızlı sorgu planının derlenmesi sırasında optimizer tarafından önerilen dizini uygulamayı düşünüyorum:

/*
The Query Processor estimates that implementing the following index could improve
the query cost by 98.8091%.

WARNING: This is only an estimate, and the Query Processor is making this 
recommendation based solely upon analysis of this specific query.
It has not considered the resulting index size, or its workload-wide impact,
including its impact on INSERT, UPDATE, DELETE performance.
These factors should be taken into account before creating this index.
*/
CREATE NONCLUSTERED INDEX [<Name of Missing Index>]
ON [dbo].[PDetail] ([ClientID],[PostedDate])
INCLUDE ([Amount]);

Dizin, bir ON PartitionSchemeName (PostedDate)maddeye göre, bölüme göre hizalanmalıdır, ancak asıl mesele, açıkça en iyi veri erişim yolunun sağlanmasının, OPTIMIZE FOR UNKNOWNyerel değişkenleri kullanmak gibi ipuçlarına veya eski moda geçici çözümlere başvurmadan optimize edicinin kötü plan seçimlerinden kaçınmasına yardımcı olacağıdır .

Geliştirilmiş endeks ile, Amountsütunu almak için Anahtar Arama ortadan kalkacak, sorgu işlemcisi hala dinamik bölüm atma işlemini gerçekleştirebilir ve belirli ClientIDve tarih aralığını bulmak için bir arama kullanabilir .


Keşke iki cevabı doğru olarak işaretleyebilseydim, ama tekrar, ek bilgi için teşekkürler - çok öğretici.
RThomas

1
Bunu gönderdiğimden bu yana birkaç yıl geçti ... ama sadece size bildirmek istedim. Ben hala bütün garip zamanları "yanlış anlaşılır" terimini kullanıyorum ve yaptığım zaman hep Paul White'ı düşünüyorum. Beni her zaman kıkırdatır.
RThomas

0

Saklı bir prosedürün yavaşladığı durumlarda da aynı sorunu yaşadım OPTIMIZE FOR UNKNOWNve RECOMPILEsorgu ipuçları yavaşlığı giderdi ve yürütme süresini hızlandırdı. Ancak, aşağıdaki iki yöntem saklı yordamın yavaşlığını etkilemedi: (i) WITH RECOMPILE kullanarak önbelleği temizleme (ii). Yani, dediğiniz gibi, gerçekten koklayıcı koklama değildi.

2389 ve 2390 iz bayrakları da yardımcı olmadı. Sadece istatistikleri ( EXEC sp_updatestats) güncelleme benim için yaptı.

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.