Histogram dışındaki kardinalite tahmini


14

Kurmak

Bir kardinalite tahminini anlamakta sorun yaşıyorum. İşte benim test kurulumum:

  • Stack Overflow veritabanının 2010 sürümü
  • SQL Server 2017 CU15 + GDR (KB4505225) - 14.0.3192.2
  • yeni CE (uyumluluk seviyesi 140)

Bu proc var:

USE StackOverflow2010;
GO

CREATE OR ALTER PROCEDURE #sp_PostsByCommentCount
    @CommentCount int
AS
BEGIN
    SELECT * 
    FROM dbo.Posts p
    WHERE 
        p.CommentCount = @CommentCount
    OPTION (RECOMPILE); 
END;
GO

dbo.PostsTabloda kümelenmemiş dizin veya istatistik yok (üzerinde kümelenmiş bir dizin var Id).

Bunun için tahmini bir plan isterken, çıkan "tahmini satırlar" dbo.Posts1.934,99'dur:

EXEC #sp_PostsByCommentCount @CommentCount = 51;

Tahmini planı istediğimde aşağıdaki istatistik nesnesi otomatik olarak oluşturuldu:

DBCC SHOW_STATISTICS('dbo.Posts', [_WA_Sys_00000006_0519C6AF]);

SSMS'deki istatistik çıktısının ekran görüntüsü

Bundan öne çıkan özellikler:

  • İstatistiklerin örnek oranı% 1.81'dir (67.796 / 3.744.192)
  • Sadece 31 histogram adımı kullanıldı
  • "Tüm yoğunluk" değeri 0.03030303(33 farklı değer örneklenmiştir)
  • Son RANGE_HI_KEYhistogramda ile, 50 EQ_ROWS1 arasında

Soru

50'den yüksek herhangi bir değerin (2,147,483,647'ye kadar ve bu değer dahil) geçmesi 1.934,99 satır tahminiyle sonuçlanır. Bu tahmini oluşturmak için hangi hesaplama veya değer kullanılır? Eski kardinalite tahmincisi bu arada 1 satırlık bir tahmin üretir.

Ne Denedim

İşte sahip olduğum bazı teoriler, denediğim şeyler veya buna bakarken kazabildiğim ek bilgi parçaları.

Yoğunluk Vektörü

Başlangıçta yoğunluk vektörü olacağını düşündüm, sanki kullandığım gibi OPTION (OPTIMIZE FOR UNKNOWN). Ancak bu istatistik nesnesinin yoğunluk vektörü 3.744.192 * 0.03030303 = 113.460, bu yüzden bu değil.

Genişletilmiş Etkinlikler

Etkinliği toplayan bir Genişletilmiş Etkinlik oturumu çalıştırmayı denedim query_optimizer_estimate_cardinality(Paul White'ın blog yazısı Cardinality Tahmini: Yoğunluk İstatistiklerini Birleştirerek öğrendim ) ve bu tür ilginç tidbitler aldım:

<CalculatorList>
  <FilterCalculator CalculatorName="CSelCalcColumnInInterval" Selectivity="-1.000" 
                    CalculatorFailed="true" TableName="[p]" ColumnName="CommentCount" />

  <FilterCalculator CalculatorName="CSelCalcAscendingKeyFilter" Selectivity="0.001" 
                    TableName="[p]" ColumnName="CommentCount" UseAverageFrequency="true" 
                    StatId="4" />
</CalculatorList>

Yani CSelCalcAscendingKeyFilterhesap makinesi kullanılmış gibi görünüyor (diğeri bunun ne anlama gelirse başarısız olduğunu söylüyor). Bu sütun bir anahtar veya benzersiz veya zorunlu olarak artan değil, her neyse.

Bu terimin bazı Google'larını yapmak beni bazı blog yayınlarına yönlendirdi:

Bu direkler, yeni CE'nin histogram dışındaki tahminleri yoğunluk vektörünün ve statün modifikasyon sayacının bir kombinasyonuna dayandığını göstermektedir. Ne yazık ki, yoğunluk vektörünü zaten dışladım (sanırım ?!) ve değişiklik sayacı sıfırdır ( sys.dm_db_stats_propertiesyine de).

İzleme Bayrakları

Forrest , tahmin süreci hakkında daha fazla bilgi almak için TF 2363'ü açmamı önerdi. Bence bu çıktıdan en alakalı şey şudur:

Plan for computation:

  CSelCalcAscendingKeyFilter(avg. freq., QCOL: [p].CommentCount)

Selectivity: 0.000516798

Bu bir atılımdır (teşekkürler, Forrest!): Bu 0.000516798sayı ( Selectivity="0.001"yukarıdaki XE özelliğinde yararsız bir şekilde yuvarlanmış gibi görünüyor ) tablodaki satır sayısıyla çarpıldığında aradığım tahmin (1,934,99).

Muhtemelen bariz bir şeyi kaçırıyorum, ancak bu seçicilik değerinin CSelCalcAscendingKeyFilterhesap makinesinin içinde nasıl üretildiğini tersine çeviremedim .

Yanıtlar:


13

Testlerime dayanarak, sınırların dışındaki kardinalite tahmini, satır sayısının kare köküdür, son istatistik güncellemesinden bu yana eklenen satır sayısıyla sınırlı ve yukarıda değer başına ortalama satırlarla sınırlanmıştır.

Sizin durumunuzda, 1.934.99 = SQRT (3744192)

Aşağıdaki test kurulumu:

--setup
USE TestDB
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS OFF
GO

DROP TABLE IF EXISTS dbo.Hist

CREATE TABLE dbo.Hist (
ID int identity primary key,
Num int
)

INSERT dbo.Hist
SELECT TOP 300
(ROW_NUMBER() OVER(ORDER BY(SELECT 1/0)))%3
FROM master..spt_values a
CROSS JOIN master..spt_values b
--Get estimated plan
--don't forget to run right after setup to auto-create stats
SELECT *
FROM dbo.Hist
WHERE Num = 1000
--gradually add rows, then rerun estimate above
INSERT dbo.Hist
SELECT TOP 100
-1
FROM master..spt_values a
--I sure hope you weren't testing this in prod (cleanup)
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS ON
GO

Şaşırtıcı bir şekilde, bu yaklaşımdan satır tahminleri bile üretildi: 400 toplam satırda 20, 900'de 30, 1600'de 40, vb.

Bununla birlikte, son 10000 rakamı, mevcut tahminlerde değer başına satır sayısı olan satır tahmini maksimum 100 olur. Sadece 10 satır eklemek tahmini 10 olarak ayarlayacaktır, çünkü sqrt (300)> 10.

Böylece tahminler bu formül kullanılarak ifade edilebilir:

Estimate = MIN(SQRT(AC), MIN(AR, MC))

İstatistikler örneklenirse, MC'nin dikkate alınmadığını unutmayın. Böylece formül şöyle olur:

Estimate = MIN(SQRT(AC), AR))

Nerede

  • MC "değişiklik sayısı" dır (istatistikler oluşturulduğundan beri yapılan değişiklik sayısı)
  • AC, "ayarlanmış kardinalite" dir (istatistik artı MC'den satır sayısı),
  • AR, değer başına ortalama satırdır (istatistikteki satırların sayısı sütundaki farklı değerlere bölünür)

Bu tahminlerin formülleri ve hesap makinesiyle ilgili diğer ayrıntılar bu blog gönderisinde bulunabilir: CSelCalcAscendingKeyFilter Hesap Makinesi'nden Tahminleri Analiz Etme

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.