统计数据是最新的,但估计不正确

use*_*923 12 sql-server statistics sql-server-2008-r2 index-statistics

当我这样做时,dbcc show_statistics ('Reports_Documents', PK_Reports_Documents)我会得到报告 ID 18698 的以下结果:

在此处输入图片说明

对于此查询:

SELECT * 
FROM Reports_Documents 
WHERE ReportID = 18698 option (recompile)
Run Code Online (Sandbox Code Playgroud)

我得到一个查询计划,PK_Reports_Documents按预期进行聚集索引搜索。

但让我感到困惑的是估计行数的错误值:

在此处输入图片说明

根据这个

当示例查询 WHERE 子句值等于直方图 RANGE_HI_KEY 值时,SQL Server 将使用直方图中的 EQ_ROWS 列来确定等于的行数

这也是我所期望的方式,但在现实生活中似乎并非如此。我还尝试RANGE_HI_KEY了由提供的直方图中存在的一些其他值,show_statistics并经历了相同的情况。在我的情况下,这个问题似乎导致某些查询使用非常不理想的执行计划,导致执行时间为几分钟,而我可以通过查询提示在 1 秒内运行它。

总而言之:有人可以解释一下为什么EQ_ROWS直方图没有用于估计的行数,不正确的估计来自哪里?

更多(可能有用)信息:

  • 自动创建统计已开启,所有统计都是最新的。
  • 被查询的表大约有 8000 万行。
  • PK_Reports_Documents是一个组合PK,由ReportID INTDocumentID CHAR(8)

该查询似乎总共加载了 5 个不同的统计对象,所有这些对象都包含ReportID表中的 + 一些其他列。它们都已新鲜更新。RANGE_HI_KEY下表中是直方图中的最高上限列值。

+-------------------------------------------------------------------------+----------+--------------+--------------+---------------------+--------------+------------+----------+---------------------+----------------+
|                                  name                                   | stats_id | auto_created | user_created | Leading column Type | RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS  | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+-------------------------------------------------------------------------+----------+--------------+--------------+---------------------+--------------+------------+----------+---------------------+----------------+
| PK_Reports_Documents                                                    |        1 |            0 |            0 | Stationary          |        18722 | 0          | 2228,526 |                   0 | 1              |
| _dta_index_Reports_Documents_42_1629248859__K1_K63_K14_K13_K22_K23_72_6 |       62 |            0 |            0 | Stationary          |        18698 | 0          | 2228,526 |                   0 | 1              |
| _dta_stat_1629248859_1_1_59                                             |       76 |            0 |            1 | Stationary          |        18686 | 50,56393   | 1        |                   0 | 13397,04       |
| _dta_stat_1629248859_1_22_14_18_12_6                                    |       95 |            0 |            1 | Stationary          |        18698 | 0          | 2228,526 |                   0 | 1              |
| _dta_stat_1629248859_1_7_14_4_23_62                                     |       96 |            0 |            1 | Stationary          |        18698 | 56,63327   | 21641,5  |                   0 | 14526,44       |
+-------------------------------------------------------------------------+----------+--------------+--------------+---------------------+--------------+------------+----------+---------------------+----------------+
Run Code Online (Sandbox Code Playgroud)

sp_updatestats 计划每晚运行以更新统计信息。

Aar*_*and 10

对此有一个简单的解决方案:

放弃所有_dta_...统计数据并停止盲目应用 DTA 建议。

更多信息

特殊的问题是所讨论的列有多组统计信息。额外的dta统计数据是通过对数据进行采样创建的(与索引无关的统计数据的默认行为)。

与采样统计数据的情况一样,生成的直方图并未涵盖所有相关数据。问题中的查询碰巧选择了一个在直方图之外的值,从而得到了 1 行的估计值。

当同一列存在多组统计信息时,查询优化器的确切行为没有完全记录。它确实倾向于比采样更喜欢“完整扫描”统计信息,但它也更喜欢最近更新的统计信息而不是旧的统计信息。