LIKE operatörü için Kardinalite Tahmini (Yerel Değişkenler)


24

LIKEİşleci bilinmeyen senaryolar için tüm optimizasyonlarda kullanırken hem eski hem de yeni CE'lerin% 9'luk bir tahmin kullandığı izlenimi altındaydım (ilgili istatistiklerin mevcut olduğunu ve sorgu iyileştiricinin seçicilik tahminlerine başvurmak zorunda olmadığını varsayarak).

Kredi veritabanına karşı aşağıdaki sorgu yürütülürken, farklı CE'ler altında farklı tahminler alıyorum. Yeni CE kapsamında beklediğim 900 satırlık bir tahminde bulunuyorum, eski CE altında 241.416 bir tahminde bulunuyorum ve bu tahminin nasıl elde edildiğini çözemiyorum. Herhangi bir ışık tutabilecek biri var mı?

-- New CE (Estimate = 900)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName;

-- Forcing Legacy CE (Estimate = 241.416)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName
OPTION (
QUERYTRACEON 9481,
QUERYTRACEON 9292,
QUERYTRACEON 9204,
QUERYTRACEON 3604
);

Senaryomda zaten 120 kredi uyumluluk seviyesine ayarlanmış kredi veri tabanına sahibim, bu yüzden neden ikinci sorguda eski CE'yi zorlamak ve ayrıca en iyi duruma getirici tarafından hangi istatistiklerin kullanıldığı / dikkate alındığı hakkında bilgi vermek için iz bayrakları kullanıyorum. 'Soyadı' sütun istatistiklerinin kullanıldığını görebiliyorum ancak 241.416 tahmininin nasıl elde edildiğini hala çözemiyorum.

"LIKE öngörüsünü tüm bilinmeyen senaryolarda optimize ederken, hem eski hem de yeni CE'ler yüzde 9'luk bir tahmin kullanıyor" ifadesini içeren Itzik Ben-Gan makalesinden başka çevrimiçi bir şey bulamadım . Bu gönderideki bilgiler yanlış görünüyor.

Yanıtlar:


28

LIKE Sizin durumunuzdaki tahmin aşağıdakilere dayanmaktadır:

  • G: Standart% 9 tahmin ( sqllang!x_Selectivity_Like)
  • M: 6 faktörü (sihirli sayı)
  • D: Ortalama veri uzunluğu bayt olarak (istatistiklerden), tam sayıya yuvarlanır

Özellikle, sqllang!CCardUtilSQL7::ProbLikeGuesskullanır:

Selectivity (S) = G / M * LOG(D)

Notlar:

  • LOG(D)Eğer terimi atlanmıştır D1 ve 2 arasındadır.
  • Eğer D1'den az olduğu (eksik veya dahil NULListatistik):
    D = FLOOR(0.5 * maximum column byte length)

Bu tür bir tuhaflık ve karmaşıklık orijinal CE'ye oldukça tipiktir.

Soru örneğinde, ortalama uzunluk 5'tir ( DBCC SHOW_STATISTICSaşağı doğru 5,6154 ):

Tahmini = 10.000 * (0.09 / 6 * LOG (5)) = 241.416

Diğer örnek değerler:

 D   = S için formül kullanarak tahmin et
 15 = 406.208
 14 = 395.859
 13 = 384.742
 12 = 372.736
 11 = 359.684
 10 = 345.388
 09 = 329.584
 08 = 311.916
 07 = 291.887
 06 = 268.764
 05 = 241,416
 04 = 207.944
 03 = 164.792
 02 = 150.000 (LOG kullanılmıyor)
 01 = 150.000 (LOG kullanılmıyor)
 00 = 291.887 (LOG 7) / * ZEMİN (0.5 * 15) [15, soyadı varchar (15)] olduğundan 15

Test donanımı

DECLARE
    @CharLength integer = 5, -- Set length here
    @Counter integer = 1;

CREATE TABLE #T (c1 varchar(15) NULL);

-- Add 10,000 rows
SET NOCOUNT ON;
SET STATISTICS XML OFF;

BEGIN TRANSACTION;
WHILE @Counter <= 10000
BEGIN
    INSERT #T (c1) VALUES (REPLICATE('X', @CharLength));
    SET @Counter = @Counter + 1;
END;
COMMIT TRANSACTION;

SET NOCOUNT OFF;
SET STATISTICS XML ON;

-- Test query
DECLARE @Like varchar(15);
SELECT * FROM #T AS T 
WHERE T.c1 LIKE @Like;

DROP TABLE #T;

15

SQL Server 2014'te eski CE ile test ettim ve% 9'luk bir tahmin olarak da almadım. Çevrimiçi olarak doğru bir şey bulamadım, bazı testler yaptım ve denediğim tüm test senaryolarına uygun bir model buldum, ancak tam olduğundan emin olamadım.

Bulduğum modelde, tahmin tablodaki satır sayısından, filtrelenmiş sütunun istatistiklerinin ortalama anahtar uzunluğundan ve bazen de filtrelenmiş sütunun veri türü uzunluğundan elde edilir. Tahmin için kullanılan iki farklı formül vardır.

FLOOR (ortalama anahtar uzunluğu) = 0 ise, tahmin formülü sütun istatistiklerini dikkate almaz ve veri türü uzunluğuna dayalı bir tahmin oluşturur. Sadece VARCHAR (N) ile test ettim, bu yüzden NVARCHAR (N) için farklı bir formül olabilir. VARCHAR (N) için formül:

(satır tahmini) = (tablodaki satırlar) * (-0.004869 + 0.032649 * log10 (veri türünün uzunluğu))

Bu çok güzel bir uyum var, ama tam olarak doğru değil:

ilk formül grafiği

X ekseni veri türünün uzunluğu ve y ekseni 1 milyon satır içeren bir tablo için tahmini satır sayısıdır.

Sorgu optimize edici, eğer sütunda istatistiklere sahip değilseniz veya sütun ortalama anahtar uzunluğunu 1'in altına düşürmek için yeterli NULL değerine sahipse bu formülü kullanır.

Örneğin, VARCHAR'da (50) filtre uygulayan ve sütun istatistikleri olmayan 150k satırlık bir tablonuz olduğunu varsayalım. Satır tahmini tahmini:

150000 * (-0,004869 + 0,032649 * log10 (50)) = 7590,1 satır

Sınamak için SQL:

CREATE TABLE X_CE_LIKE_TEST_1 (
STRING VARCHAR(50)
);

CREATE STATISTICS X_STAT_CE_LIKE_TEST_1 ON X_CE_LIKE_TEST_1 (STRING) WITH NORECOMPUTE;

WITH
    L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
    L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
    L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
    L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
    L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B CROSS JOIN L2 C),
    NUMS AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS NUM FROM L4)  
    INSERT INTO X_CE_LIKE_TEST_1 WITH (TABLOCK) (STRING)
    SELECT TOP (150000) 'ZZZZZ'
    FROM NUMS
    ORDER BY NUM;

DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM X_CE_LIKE_TEST_1
WHERE STRING LIKE @LastName;

SQL Server, 7242.47 bir tahmini satır sayısı verir ve bu yakın bir değerdir.

FLOOR (ortalama anahtar uzunluğu)> = 1 ise, FLOOR (ortalama anahtar uzunluğu) değerini temel alan farklı bir formül kullanılır. İşte denediğim bazı değerlerin tablosu:

1    1.5%
2    1.5%
3    1.64792%
4    2.07944%
5    2.41416%
6    2.68744%
7    2.91887%
8    3.11916%
9    3.29584%
10   3.45388%

FLOOR (ortalama anahtar uzunluğu) <6 ise, yukarıdaki tabloyu kullanın. Aksi takdirde, aşağıdaki denklemi kullanın:

(satır tahmini) = (tablodaki satırlar) * (-0.003381 + 0.034539 * log10 (ZEMİN (ortalama anahtar uzunluğu)))

Bu bir diğerinden daha iyi bir uyuma sahip, ancak yine de tam olarak doğru değil.

ikinci formül grafiği

X ekseni, ortalama anahtar uzunluğu ve y ekseni, 1 milyon satır içeren bir tablo için tahmini satır sayısıdır.

Başka bir örnek vermek gerekirse, filtrelenmiş sütundaki istatistikler için ortalama anahtar uzunluğu 5.5 olan 10k satırlı bir tablonuz olduğunu varsayalım. Satır tahmini şöyle olur:

10000 * 0.241416 = 241.416 satır.

Sınamak için SQL:

CREATE TABLE X_CE_LIKE_TEST_2 (
STRING VARCHAR(50)
);

WITH
    L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
    L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
    L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
    L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
    L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B CROSS JOIN L2 C),
    NUMS AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS NUM FROM L4)  
    INSERT INTO X_CE_LIKE_TEST_2 WITH (TABLOCK) (STRING)
    SELECT TOP (10000) 
    CASE 
      WHEN NUM % 2 = 1 THEN REPLICATE('Z', 5) 
      ELSE REPLICATE('Z', 6)
    END
    FROM NUMS
    ORDER BY NUM;

CREATE STATISTICS X_STAT_CE_LIKE_TEST_2 ON X_CE_LIKE_TEST_2 (STRING) 
WITH NORECOMPUTE, FULLSCAN;

DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM X_CE_LIKE_TEST_2
WHERE STRING LIKE @LastName;

Satır tahmini, soruyla neye uyduğunu belirten 241.416'dır. Tabloda olmayan bir değer kullanırsam bazı hatalar olur.

Buradaki modeller mükemmel değil ama genel davranışı oldukça iyi gösterdiklerini düşünüyorum.

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.