Dökülmelerin tempdb'ye düşme şansını azaltmak için satır tahminleri nasıl geliştirilebilir?


11

Tempdb olayları (yavaş sorgulara neden) dökülme olduğunda genellikle satır tahminleri belirli bir katılmak için yol olduğunu fark ettim. Dökülme olaylarının birleştirme ve karma birleştirmelerle gerçekleştiğini gördüm ve genellikle çalışma süresini 3x ila 10x artırdılar. Bu soru, dökülme olayları olasılığını azaltacağı varsayımı altında satır tahminlerinin nasıl iyileştirileceği ile ilgilidir.

Gerçek Sıra Sayısı 40k.

Bu sorgu için, plan hatalı satır tahmini gösterir (11.3 satır):

select Value
  from Oav.ValueArray
 where ObjectId = (select convert(bigint, Value) NodeId
                     from Oav.ValueArray
                    where PropertyId = 3331  
                      and ObjectId = 3540233
                      and Sequence = 2)
   and PropertyId = 2840
option (recompile);

Bu sorgu için, plan iyi satır tahmini gösterir (56 bin satır):

declare @a bigint = (select convert(bigint, Value) NodeId
                       from Oav.ValueArray
                      where PropertyId = 3331
                        and ObjectId = 3540233
                        and Sequence = 2);

select Value
  from Oav.ValueArray
 where ObjectId = @a               
   and PropertyId = 2840
option (recompile);

İlk vaka için satır tahminlerini iyileştirmek için istatistikler veya ipuçları eklenebilir mi? Belirli filtre değerleri (property = 2840) ile istatistik eklemeyi denedim ama ya kombinasyon doğru alamadım ya da ObjectId derleme zamanında bilinmediği ve belki de tüm ObjectIds üzerinde bir ortalama seçiyor çünkü yok sayılıyor.

Önce prob sorgusunu yapacak ve daha sonra bunu satır tahminlerini belirlemek için kullanacak herhangi bir mod var mı veya körü körüne uçmalı mı?

Bu özellik, birkaç nesne üzerinde birçok değere (40k) ve büyük çoğunlukta sıfır değerine sahiptir. Belirli bir birleştirme için beklenen maksimum satır sayısının belirtilebileceği bir ipucundan memnun olurum. Bazı parametreler birleştirme işleminin parçası olarak dinamik olarak belirlenebilir veya bir görünüme daha iyi yerleştirilebilir (değişkenler için destek yoktur), çünkü bu genellikle akıldan çıkmayan bir sorundur.

Dökülmelerin tempdb'ye düşme olasılığını en aza indirmek için ayarlanabilecek herhangi bir parametre var mı (örneğin sorgu başına minimum bellek)? Sağlam planın tahmin üzerinde bir etkisi yoktu.

2013.11.06'yı düzenleyin : Yorumlara ve ek bilgilere yanıt:

İşte sorgu planı görüntüleri. Uyarılar, convert () ile kardinalite / seek yüklemi ile ilgilidir:

resim açıklamasını buraya girin resim açıklamasını buraya girin

@Aaron Bertrand'ın yorumuna göre, convert () yöntemini bir test olarak değiştirmeyi denedim:

create table Oav.SeekObject (
       LookupId bigint not null primary key,
       ObjectId bigint not null
);

insert into Oav.SeekObject (
   LookupId, ObjectId
) VALUES (
   1, 3540233
) 

select Value
  from Oav.ValueArray
 where ObjectId = (select ObjectId 
                     from Oav.SeekObject 
                    where LookupId = 1)
   and PropertyId = 2840
option (recompile);

resim açıklamasını buraya girin

Garip ama başarılı bir ilgi noktası olarak, aramaya kısa devre yapmasına izin verdi:

select Value
  from Oav.ValueArray
 where ObjectId = (select ObjectId 
                     from Oav.ValueArray
                    where PropertyId = 2840
                      and ObjectId = 3540233
                      and Sequence = 2)
   and PropertyId = 2840
option (recompile);

resim açıklamasını buraya girin

Her ikisi de uygun bir anahtar araması listeler, ancak yalnızca ilk olanlar ObjectId öğesinin "Çıktısını" listeler. Sanırım ikincisi gerçekten kısa devre mi?

Birisi, satır tahminlerine yardımcı olmak için tek sıra probların yapılıp yapılmadığını doğrulayabilir mi? Tek satırlı bir PK araması histogramdaki aramanın doğruluğunu büyük ölçüde artırabildiğinde (özellikle dökülme potansiyeli veya geçmişi varsa) optimizasyonu yalnızca histogram tahminleriyle sınırlamak yanlış görünüyor. Gerçek bir sorguda bu alt birleşimlerden 10 tanesi varsa, ideal olarak paralel olarak gerçekleşirler.

Yan not, sql_variant temel türünü (SQL_VARIANT_PROPERTY = BaseType) alanın kendisinde sakladığından, "doğrudan" dönüştürülebilir olduğu sürece (örn. int veya belki de bigint'e int). Bu derleme zamanında bilinmediğinden, ancak kullanıcı tarafından bilinebildiğinden, belki sql_variants için bir "AssumeType (type, ...)" işlevi daha şeffaf bir şekilde işlem görmelerine izin verir.


1
İlk tahmin, bigint'e dönüştürmenin tahminlerinizi atmasıdır (sorgu planının SQL Server 2012'de bununla ilgili bir uyarı olacaktır), ancak diğer yandan, alt sorgunuz asla 0 veya 1 satır dışında bir şey döndüremez başarılı bir sorgu için. Sahip olduğunuz sorgu planlarını görmek ilginç olurdu. Belki de XML sürümüne bir bağlantı olarak.
Mikael Eriksson

2
Alt sorguyu satır içine alarak ne kazanırsınız? Ayrı olarak çıkarmanın genel olarak daha net olduğunu ve daha iyi tahminlere yol açtığı için, neden sadece bu yöntemi kullanmıyorsunuz?
Aaron Bertrand

2
SQL Server'ın hangi sürümü? Sorun ayrıntılarını görebilmemiz için tablolar için tablo ve dizin DDL ve istatistik blobları (tek ve çok sütunlu) sağlayabilir misiniz? Sorguyu declare @a bigint = yaptığınız gibi bölmek benim için doğal bir çözüm gibi görünüyor, bu neden kabul edilemez?
Paul White 9

2
Sanırım tasarımınız sizi CONVERT()sütunlarda kullanmaya ve daha sonra onlara katılmaya zorlayan (çok basit) bir EAV tasarımı . Bu kesinlikle verimli değildir çoğu durumda. Bu özel birinde, dönüştürülecek tek bir değerdir, bu muhtemelen bir sorun değildir, ancak tabloda hangi dizinler var? EAV tasarımları genellikle sadece uygun indeksleme ile iyi performans gösterir (bu genellikle dar tablolarda çok sayıda indeks anlamına gelir).
ypercubeᵀᴹ

@ Paul White, bölünürken ... bu durum için bir çözüm kadar iyi. Ancak daha genel / karmaşık için çoğunlukla paralelleştirme ve okunabilirlikten vazgeçmek istemiyorum. Ben bir sorgu içinde alt sorgular (bazıları daha karmaşık olan) olarak 10 var ama sorgunun geri kalanı başlamadan önce sadece 5 "olgun" olması gerektiğini varsayalım - bu 5 hangisi olduğunu anlamak zorunda kalmak istiyorum.
crokusek

Yanıtlar:


7

Dökülmeler, tempdb veya ipuçları hakkında yorum yapmayacağım çünkü sorgu bu kadar dikkate alınması oldukça basit görünüyor. Sorgu için uygun dizinler varsa SQL Server'ın optimize edici işini oldukça iyi yapacağını düşünüyorum.

Ayrıca, hangi dizinlerin yararlı olacağını gösterdiği için iki sorguya bölmeniz iyidir. İlk bölüm:

(select convert(bigint, Value) NodeId
 from Oav.ValueArray
 where PropertyId = 3331  
   and ObjectId = 3540233
   and Sequence = 2)

(PropertyId, ObjectId, Sequence)dahil olmak üzere bir dizine ihtiyacı var Value. UNIQUEGüvende olurdum . Sorgu, birden fazla satır döndürülürse çalışma sırasında yine de hata atar, bu nedenle benzersiz dizinde bunun gerçekleşmeyeceğinden emin olmak iyidir:

CREATE UNIQUE INDEX
    PropertyId_ObjectId_Sequence_UQ
  ON Oav.ValueArray
    (PropertyId, ObjectId, Sequence) INCLUDE (Value) ;

Sorgunun ikinci kısmı:

select Value
  from Oav.ValueArray
 where ObjectId = @a               
   and PropertyId = 2840

aşağıdakileri (PropertyId, ObjectId)içeren bir dizine ihtiyaç duyar Value:

CREATE INDEX
    PropertyId_ObjectId_IX
  ON Oav.ValueArray
    (PropertyId, ObjectId) INCLUDE (Value) ;

Verimlilik artırılmazsa veya bu dizinler kullanılmazsa veya satır tahminlerinde hala farklılıklar varsa, bu sorguyu daha ayrıntılı incelemeniz gerekir.

Bu durumda, dönüşümler (EAV tasarımından ve farklı veri türlerinin aynı sütunlarda depolanmasından gerekir) olası bir nedendir ve sorgunuzu iki parçaya bölme çözümünüz (@AAron Bertrand ve @Paul White yorumunda olduğu gibi) doğal görünüyor ve gidilecek yol. İlgili sütunlarında farklı veri türlerine sahip olacak şekilde yeniden tasarım yapmak başka bir tasarım olabilir.


Tabloları kapsayan indeksleri vardı - Ben soruda belirtmeliydim. Örnek gerçekten daha büyük bir sorgu besleyen bir alt birleştirme, bu yüzden tempdb dökülmeleri hakkında tüm yaygara vardır.
crokusek

5

İstatistikleri geliştirmeyle ilgili açık soruya kısmi bir cevap olarak ...

Ayrı ayrı kesilen durum için bile satır tahminlerinin 10X (4k ile beklenen 40k) arasında hala kapalı olduğunu unutmayın.

İstatistik histogramı, uzun (dikey), 3.5M satırlar tablosu olduğu ve belirli bir özellik son derece seyrek olduğu için bu özellik için muhtemelen çok ince yayılmıştır.

Seyrek mülk için ek istatistikler (IX istatistikleriyle biraz fazla) oluşturun:

create statistics [STAT_ValueArray_ObjPropValue_WhereProp2840] ON [Oav].[ValueArray](ObjectId, PropertyId, Value)
where PropertyId = 2840

Orijinalleri:

resim açıklamasını buraya girin resim açıklamasını buraya girin

Convert () kaldırıldığında (uygun):

resim açıklamasını buraya girin

Convert () kaldırıldığında (kısa devre):

resim açıklamasını buraya girin

Nesnelerin% 99.9'unun üzerinde Özellik 2840 tanımlanmadığı için ~ 2X oranında hala kapalı. Aslında, bu test durumu için, özellik, 3.5M satır tablosunun 200 bin farklı Nesnesinin sadece 1'inde bulunur. Şaşırtıcı o gerçekten yakın var. Filtreyi daha az ObjectIds olacak şekilde ayarlama,

create statistics [STAT_ValueArray_ObjPropValue_WhereProp2840] ON [Oav].[ValueArray](ObjectId, PropertyId, Value)
where PropertyId = 2840 and ObjectId >= 3540000 and ObjectId < 3541000

create statistics [STAT_ValueArray_ObjPropValue_WhereProp2840] ON [Oav].[ValueArray](ObjectId, PropertyId, Value)
where PropertyId = 2840 and ObjectId = 3540233;

Hmm, değişiklik yok ... İstatistiklerin sonuna "tam tarama ile" eklendi (önceki iki neden işe yaramadı olabilir) ve evet:

create statistics [STAT_ValueArray_ObjPropValue_WhereProp2840] ON [Oav].[ValueArray](ObjectId, PropertyId, Value)
where PropertyId = 2840 with full scan;

resim açıklamasını buraya girin

Yaşasın. Bu nedenle, geniş ölçüde kapsayan bir IX'a sahip oldukça dikey bir tabloda, ek filtrelenmiş istatistikler eklemek büyük bir gelişme gibi görünmektedir (özellikle seyrek ancak çok değişken tuş kombinasyonları için).


Çok sütunlu istatistiklerle ilgili bazı sorunlu sorunların bağlantısı .
crokusek
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.