我试图了解 SQL Server 如何估计以下 Stack Overflow 数据库查询的基数
首先,我创建索引
CREATE INDEX IX_PostId ON dbo.Comments
(
PostId
)
INCLUDE
(
[Text]
)
这是查询:
SELECT u.DisplayName,
c.PostId,
c.Text
FROM Users u
JOIN Comments c
ON u.Reputation = c.PostId
WHERE u.AccountId = 22547
执行计划在这里
首先,SQL Server 扫描用户表上的聚集索引以返回与 AccountId 谓词匹配的用户。我可以看到它使用了这个统计数据:_WA_Sys_0000000E_09DE7BCC
我可以看到该用户没有范围高键,因此 SQL Server 使用 avg_range 行并估计 1
评论索引搜索的搜索谓词是
soScalar Operator([StackOverflow2010].[dbo].[Users].[Reputation] as [u].[Reputation]
表示 users 表中 accountId 为 User(s) 的信誉值22547
我可以看到总共加载了三个统计数据:
_WA_Sys_0000000E_09DE7BCC
- Users.AccountId(用于估计聚簇索引查找谓词)
IX_PostId
- Comments.PostId(用于估计Index seek predicate)
_WA_Sys_0000000A_09DE7BCC
- Users.Reputation (?)
SQL Server 如何得出索引搜索的估计值?22547
它无法在编译时知道 accountId 的信誉,因为帐户 ID 统计信息不显示这一点,因此它无法对 IX_PostId 的直方图执行查找。我可以看到声誉统计数据也已加载,那么它是否以某种方式同时使用了两者?
此查询针对 CE 150 运行
在这种特殊情况下,SQL Server 不会为 Comments 表上的索引查找得出基数估计,因为它不需要。让我稍微解释一下这句话:
编译过程总是涉及初始轮的基数估计,其中估计是根据简化后查询的逻辑表示的早期形状得出的。您示例中的逻辑树是:
需要两个初步估计:
LogOp_Select
)LogOp_Join
)暂时搁置这些计算的细节,事实是 SQL Server 确实以某种方式推导出了两者的估计选择性(和基数)。假设过滤器后的基数估计为C 1,连接后的基数估计为C 2。
在以后基于成本的优化过程中,SQL Server 会考虑不同的方式来实现连接。例如,它可能会得出Merge Join、Hash Join、Nested Loops Join或Apply(相关循环连接)的估计成本。
在考虑应用时(使用类似 的规则),优化器已经对连接的顶部输入C 1
JNtoIdxLookup
进行了估计。它还已经知道联接结果C 2的基数。为了便于讨论,假设C 1为 10,C 2为 250。无需为较低的Apply输入生成新的估计值。我们知道它将执行 10 次(每个上部输入行一次)并且连接将总共产生 250 行。因此,较低输入的每次迭代都需要生成 25 行以使数字相加,即 10 * 25 = 250。
对你的问题的简单回答是,在这种情况下,优化器不会为索引搜索生成基数估计——它直接来自现有的连接和过滤器估计,通过考虑将逻辑连接实现为 Apply 的规则与索引查找。
其他详情
无法回避的事实是选择性计算可能极其复杂。我在上面给了你一个简单的答案,因为这似乎解决了你的问题。其他人可能需要更多细节。
我不能在这里描述整个估算框架,因为我不知道所有的细节,即使我知道,也需要几本书才能涵盖。也就是说,有一些值得一提的事情和一些其他资源可供感兴趣的读者链接。
Stack Overflow 示例数据库中的AccountId是一个未声明的键——它对每个用户都是唯一的。该信息应该通过唯一约束或索引强制执行并传达给优化器。
抽样统计数据可以方便地避免过多的编译时间,但它们可能会产生误导性的画面。除非您特别希望了解高度复杂的统计抽样世界,否则您应该使用完整扫描创建或更新统计信息以获得可重复的高质量结果。
SQL Server 在初始估计之前尝试转换子查询并应用于连接。这并不总是可能的,因此在某些情况下,应用的估计值(可能使用内部索引查找)是直接得出的。这通常被建模为一系列点查找。如果您将查询重写为无法由 SQL Server 转换为联接的申请表,您将使用不同的方法获得不同的估计值。这只是野兽的本性。
推导估计是一个昂贵的过程,因此 SQL Server 尽可能避免它。一般而言,没有特别的理由支持一个估计值而不是另一个估计值。完全有可能使用“n”种不同(但逻辑上同样合理)的方法得出“n”种不同的估计。复杂的执行计划有时包含明显矛盾的估计,因为树的不同部分在不同时间使用不同的方法。同样,事情就是这样。
在您的示例中,SQL Server 可能不会对 apply 的内侧进行新的估计,但它会执行一些相关的计算来估计内侧搜索的成本,以及如果假脱机将被倒带或反弹多少次介绍。在估计“缺失索引”建议的成本节省时,会执行类似的计算。
相关问答及延伸阅读(除特别注明外均为本人):