Пав*_*лёв 13 sql-server query optimization sql-server-2014 cardinality-estimates
目前我正试图弄清楚 SQL Server 如何评估部分覆盖直方图步骤的范围谓词的基数。
在互联网上,在cardinality-estimation-for-and-for-intra-step-statistics-value我遇到了一个类似的问题,Paul White 给出了一个相当有趣的答案。
根据Paul的回答,谓词>=和>的基数估计公式(在这种情况下,我只对至少120的基数估计器模型感兴趣)如下:
对于 >:
Cardinality = EQ_ROWS + (AVG_RANGE_ROWS * (F * (DISTINCT_RANGE_ROWS - 1)))
Run Code Online (Sandbox Code Playgroud)
对于 >=:
Cardinality = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))
Run Code Online (Sandbox Code Playgroud)
我基于范围谓词使用TransactionDate列和“20140614”和“20140618”之间的日期时间范围测试了这些公式在AdventureWorks2014数据库的[Production].[TransactionHistory]表上的应用。
这个范围的直方图步骤的统计如下:
根据公式,我计算了以下查询的基数:
SELECT COUNT(1)
FROM [AdventureWorks2014].[Production].[TransactionHistory]
WHERE [TransactionDate] BETWEEN '20140615 00:00:00.000' AND '20140616 00:00:00.000'
Run Code Online (Sandbox Code Playgroud)
使用以下代码进行计算:
DECLARE @predStart DATETIME = '20140615 00:00:00.000'
DECLARE @predEnd DATETIME = '20140616 00:00:00.000'
DECLARE @stepStart DATETIME = '20140614 00:00:00.000'
DECLARE @stepEnd DATETIME = '20140618 00:00:00.000'
DECLARE @predRange FLOAT = DATEDIFF(ms, @predStart, @predEnd)
DECLARE @stepRange FLOAT = DATEDIFF(ms, @stepStart, @stepEnd)
DECLARE @F FLOAT = @predRange / @stepRange;
DECLARE @avg_range_rows FLOAT = 100.3333
DECLARE @distinct_range_rows INT = 3
DECLARE @EQ_ROWS INT = 0
SELECT @F AS 'F'
--for new cardinality estimator
SELECT @EQ_ROWS + @avg_range_rows * (@F * (@distinct_range_rows - 1) + 1) AS [new_card]
Run Code Online (Sandbox Code Playgroud)
经过计算,我得到以下结果:
根据公式,结果是150.5,但是优化器估计谓词为225.75行,如果你把谓词的上边框改为'20140617',优化器已经计算了250.833行,而使用我们得到的公式只有200.6666 行。
请告诉我,Cardinality Estimator 在这种情况下如何评估,也许我在理解引用的公式时犯了错误?
Pau*_*ite 14
SQL Server 在不同的情况下使用不同的计算。您的示例与链接的问答不同,因为您的范围完全包含在一个步骤中;它不跨越台阶边界。它也是一个有两个端点而不是一个端点的区间。编写BETWEEN
与使用>=
和编写两个单独的谓词相同<=
。
公式被修改为在步骤内针对预期的不同值的数量执行线性插值,并反映现在指定了两个范围端点(并假设存在于直方图步骤中)而不是一个。
使用问题中给出的直方图步骤:
对于带有 的查询BETWEEN '20140615' AND '20140616'
,计算为:
DECLARE
@Q1 float = CONVERT(float, CONVERT(datetime, '2014-06-15')),
@Q2 float = CONVERT(float, CONVERT(datetime, '2014-06-16')),
@K1 float = CONVERT(float, CONVERT(datetime, '2014-06-14')),
@K2 float = CONVERT(float, CONVERT(datetime, '2014-06-18')),
@RANGE_ROWS float = 301,
@DISTINCT_RANGE_ROWS float = 3;
DECLARE
@S1 float = (@Q1 - @K1) / (@K2 - @K1),
@S2 float = (@Q2 - @K1) / (@K2 - @K1);
DECLARE
@F float = @S2 - @S1;
DECLARE
@AVG_RANGE_ROWS float = @RANGE_ROWS / @DISTINCT_RANGE_ROWS;
SELECT
@AVG_RANGE_ROWS * ((@F * (@DISTINCT_RANGE_ROWS - 2)) + 2);
Run Code Online (Sandbox Code Playgroud)
...给225.75。@Q2
从'20140616'
to更改'20140617'
为250.833的结果。
两个结果都与问题中给出的结果相匹配。
归档时间: |
|
查看次数: |
218 次 |
最近记录: |