我的印象是,在所有针对未知场景的优化中使用LIKE运算符时,旧版CE和新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并且还提供有关查询优化器使用/考虑的统计信息的信息.我可以看到正在使用’lastname’的列统计信息,但我仍然无法确定如何推导出241.416的估计值.
除了this Itzik Ben-Gan article之外,我找不到任何在线内容,其中指出“当在所有优化中使用LIKE谓词用于未知场景时,旧版和新版CE都使用9%的估计值.”该帖子中的信息似乎不正确.
解决方法
在您的情况下,LIKE的猜测基于:
> G:标准的9%猜测(sqllang!x_Selectivity_Like)
> M:因子6(幻数)
> D:平均数据长度(以字节为单位)(从统计数据),向下舍入为整数
具体来说,sqllang!CCardUtilsql7 :: ProbLikeGuess使用:
Selectivity (S) = G / M * LOG(D)
笔记:
>如果D在1和2之间,则省略LOG(D)项.
>如果D小于1(包括丢失或NULL统计信息):
D = FLOOR(0.5 *最大列字节长度)
这种古怪和复杂性是原始CE的典型特征.
在问题示例中,平均长度为5(来自DBCC SHOW_STATISTICS的5.6154向下舍入):
Estimate = 10,000 * (0.09 / 6 * LOG(5)) = 241.416
其他示例值:
D = Estimate using formula for 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 (LOG not used) 01 = 150.000 (LOG not used) 00 = 291.887 (LOG 7) /* FLOOR(0.5 * 15) [15 since lastname is 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;