> =和>的步内统计值的基数估计


9

我正在尝试了解SQL Server如何尝试估计SQL Server 2014中的“大于”和“大于等于” where子句。

我想我确实了解基数估算,例如当我踏上台阶时

    select * from charge where charge_dt >= '1999-10-13 10:47:38.550'

基数估计为6672,可以很容易地计算为32(EQ_ROWS)+ 6624(RANGE_ROWS)+ 16(EQ_ROWS)= 6672(以下屏幕截图中的直方图)

在此处输入图片说明

但是当我这样做

    select * from charge where charge_dt >= '1999-10-13 10:48:38.550' 

(将时间增加到10:48,所以不是一步)

估计是4844.13。

该如何计算?

Answers:


9

唯一的困难是确定如何处理查询谓词间隔部分覆盖的直方图步骤。如问题中所述,谓词范围所覆盖的整个直方图步幅是微不足道的。

传统基数估计器

F =查询谓词涵盖的步长范围的分数(0到1之间)。

基本思想是使用F(线性插值)来确定谓词覆盖多少步内不同值。将该结果乘以每个不同值的平均行数(假设均匀性),然后将步数相等的行相加,得出基数估计值:

基数= EQ_ROWS +(AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)

相同的公式被用于>>=在传统的CE。

新基数估计器

新的CE稍微修改了以前的算法,以区分>>=

>第一,公式为:

基数= EQ_ROWS +(AVG_RANGE_ROWS *(F *(DISTINCT_RANGE_ROWS-1)))

因为>=它是:

基数= EQ_ROWS +(AVG_RANGE_ROWS *((F *(DISTINCT_RANGE_ROWS-1))+ 1))

+ 1反映,当比较涉及平等,假设匹配(包含假设)。

在问题示例中,F可以计算为:

DECLARE 
    @Q datetime = '1999-10-13T10:48:38.550',
    @K1 datetime = '1999-10-13T10:47:38.550',
    @K2 datetime = '1999-10-13T10:51:19.317';

DECLARE
    @QR float = DATEDIFF(MILLISECOND, @Q, @K2), -- predicate range
    @SR float = DATEDIFF(MILLISECOND, @K1, @K2) -- whole step range

SELECT
    F = @QR / @SR;

结果是0.728219019233034。将其插入>=具有其他已知值的公式中:

基数= EQ_ROWS +(AVG_RANGE_ROWS *((F *(DISTINCT_RANGE_ROWS-1))+ 1))
            = 16 +(16.1956 *((0.728219019233034 *(409-1))+ 1))
            = 16 +(16.1956 *((0.728219019233034 * 408)+1))
            = 16 +(16.1956 *(297.113359847077872 + 1))
            = 16 +(16.1956 * 298.113359847077872)
            = 16 + 4828.1247307393343837632
            = 4844.1247307393343837632
            = 4844.12473073933(浮动精度)

该结果与问题中所示的4844.13一致。

使用旧版CE的同一查询(例如,使用跟踪标志9481)应产生以下估计:

基数= EQ_ROWS +(AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)
            = 16 +(16.1956 * 0.728219019233034 * 409)
            = 16 + 4823.72307468722
            = 4839.72307468722

请注意,对于旧版CE >>=使用旧版CE ,估算值相同。


4

当过滤器“大于”或“小于”时,用于估算行的公式有点愚蠢,但这是您可以得出的数字。

号码

使用步骤193,以下是相关数字:

RANGE_ROWS = 6624

EQ_ROWS = 16

AVG_RANGE_ROWS = 16.1956

上一步的RANGE_HI_KEY = 1999-10-13 10:47:38.550

当前步骤中的RANGE_HI_KEY = 1999-10-13 10:51:19.317

来自WHERE子句的值= 1999-10-13 10:48:38.550

公式

1)在两个范围高键之间找到毫秒

SELECT DATEDIFF (ms, '1999-10-13 10:47:38.550', '1999-10-13 10:51:19.317')

结果是220767 ms。

2)调整行数

我们需要找到每毫秒的行,但在此之前,我们必须从RANGE_ROWS中减去AVG_RANGE_ROWS:

6624-16.1956 = 6607.8044行

3)用调整后的行数计算每毫秒的行数:

6607.8044行/ 220767毫秒= 0.0299311行/毫秒

4)计算WHERE子句中的值与当前步骤RANGE_HI_KEY之间的ms

SELECT DATEDIFF (ms, '1999-10-13 10:48:38.550', '1999-10-13 10:51:19.317')

这给了我们160767毫秒。

5)根据每秒的行数计算此步骤中的行:

.0299311行/毫秒* 160767毫秒= 4811.9332行

6)还记得我们之前如何减去AVG_RANGE_ROWS吗?是时候添加它们了。现在我们已经完成了与每秒行数相关的计算,我们也可以安全地添加EQ_ROWS了:

4811.9332 + 16.1956 + 16 = 4844.1288

四舍五入,这就是我们的4844.13估计。

测试公式

我找不到关于为何在计算每毫秒行数之前减去AVG_RANGE_ROWS的文章或博客文章。我能确认他们是占了估算,但仅在过去的毫秒-从字面上。

使用WideWorldImporters数据库,我进行了一些增量测试,发现行估计值的减少是线性的,直到步骤结束为止,在此步骤中,突然考虑了1x AVG_RANGE_ROWS。

这是我的示例查询:

SELECT PickingCompletedWhen
FROM Sales.Orders
WHERE PickingCompletedWhen >= '2016-05-24 11:00:01.000000'

我更新了PickingCompletedWhen的统计信息,然后得到了直方图:

DBCC SHOW_STATISTICS([sales.orders], '_WA_Sys_0000000E_44CA3770')

_WA_Sys_0000000E_44CA3770的直方图(最近3个步骤)

为了了解随着我们接近RANGE_HI_KEY,估计的行数如何减少,我在整个步骤中收集了样本。减少是线性的,但是表现得好像等于AVG_RANGE_ROWS值的行数不是趋势的一部分...直到您击中RANGE_HI_KEY,然后突然下降,就像注销的未收债务一样。您可以在示例数据中看到它,尤其是在图形中。

在此处输入图片说明

请注意,行的稳步下降,直到我们达到RANGE_HI_KEY,然后突然减去最后一个AVG_RANGE_ROWS块的BOOM。在图中也很容易发现。

在此处输入图片说明

综上所述,AVG_RANGE_ROWS的奇数处理使计算行估计更加复杂,但是您始终可以调和CE的工作。

指数退缩呢?

指数退避是新的(自SQL Server 2014起)基数估计器使用的方法,该方法可在使用多个单列统计信息时获得更好的估计。由于此问题与一个单列统计有关,因此它不涉及EB公式。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.