Sql-Server

LIKE 運算符的基數估計(局部變數)

  • November 27, 2019

我的印像是,在LIKE對未知場景進行所有優化時,舊版和新版 CE 都使用 9% 的估計值(假設相關統計數據可用並且查詢優化器不必求助於選擇性猜測)。

在對信用數據庫執行以下查詢時,我在不同的 CE 下得到不同的估計。在新的 CE 下,我收到了預期的 900 行的估計值,在舊版 CE 下,我收到了 241.416 的估計值,但我無法弄清楚這個估計值是如何得出的。有沒有人能夠闡明任何觀點?

-- 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
);

在我的場景中,我已經將信用數據庫設置為兼容級別 120,因此為什麼在第二個查詢中我使用跟踪標誌來強制使用舊版 CE,並提供有關查詢優化器使用/考慮哪些統計資訊的資訊。我可以看到正在使用“姓氏”的列統計資訊,但我仍然無法計算出 241.416 的估計值是如何得出的。

除了這篇 Itzik Ben-Gan 文章外,我在網上找不到任何東西,該文章指出“在所有優化未知場景中使用 LIKE 謂詞時,舊版和新版 CE 都使用 9% 的估計值。”。該文章中的資訊似乎不正確。

LIKE 在你的情況下的猜測是基於:

  • G: 標準的 9% 猜測 ( sqllang!x_Selectivity_Like)
  • M:係數 6(幻數)
  • D:以字節為單位的平均數據長度(來自統計數據),向下舍入為整數

具體來說,sqllang!CCardUtilSQL7::ProbLikeGuess使用:

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

筆記:

  • 如果介於 1 和 2 之間,LOG(D)則省略該術語。D
  • 如果D小於 1(包括缺失或NULL統計):

D = FLOOR(0.5 * maximum column byte length)

這種古怪和復雜性是原始 CE 的典型特徵。

在問題範例中,平均長度為 5(DBCC SHOW_STATISTICS四捨五入後為 5.6154):

估計 = 10,000 * (0.09 / 6 * LOG(5)) = **241.416**

其他範例值:

**D** =**使用 S 的公式進行估計**
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(未使用日誌)
01 = 150.000(未使用日誌)
00 = 291.887 (LOG 7) /* FLOOR(0.5 * 15) [15 因為姓氏是 varchar(15)] */

試驗台

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;

引用自:https://dba.stackexchange.com/questions/153295