需要一些帮助才能理解SQL Server 2012查询计划

时间:2013-11-18 16:41:41

标签: sql-server tsql

我有以下查询:

Select TOP 5000
    CdCl.SubId
From dbo.PanelCdCl CdCl WITH (NOLOCK)
    Inner Join dbo.PanelHistory PH ON PH.SubId = CdCl.SubId
Where CdCl.PanelCdClStatusId IS NULL And PH.LastProcessNumber >= 1605
Order By CdCl.SubId

查询计划如下所示:

enter image description here

PanelCdCl和PanelHistory表在SubId上都有一个聚簇索引/主键,它是索引中唯一的列。每个表中的每个SubId只有一行。两个表的总行数约为35M。

我很好奇为什么查询计划在聚合索引列上完成连接时会在PanelHistory上显示聚簇索引扫描。

2 个答案:

答案 0 :(得分:3)

它没有扫描PanelHistory的聚集索引(SubId)来查找SubId,它正在扫描它以找到LastProcessNumber >= 1605的所有行。这是第一个合乎逻辑的步骤。

然后它同样扫描PanelCdCl以查找所有非空PanelCdClStatusId行。然后,由于它们具有相同的索引(SubId),它们都已经在Join列上排序,因此它可以在没有其他排序的情况下执行Merge-Join。 (如果不必对输入行进行重新排序,Merge-Join几乎总是最有效的。)

然后它不必对ORDER BY进行排序,因为它已经在SubId顺序。

最后,它执行TOP,它必须在其他所有内容之后(通过SQL子句逻辑执行顺序的规则)。

因此,它测试SubId值的唯一位置是在Merge-Join中,它从不将其推送到扫描。如果它改为使用Hash-Join,这可能仍然适用。仅对于嵌套循环连接,它必须将SubId测试作为搜索推送到表上,而这应该只是较低的分支,而不是较高的分支。

答案 1 :(得分:1)

合并连接运算符需要两个已排序的输入。两个表中的聚簇键为SubId,这意味着PanelHistory中的扫描将按正确顺序给出行。群集密钥包含在所有非群集密钥索引中,因此您将拥有NCI IX_PanelCdCl_PanelCdClStatusId中的所有行,其中PanelCdClStatusId is nullSubId排序,因此也可以直接使用合并加入。

您在此处看到的实际上是两次扫描,PanelHistory中的一个聚类键,LastProcessNumber > 1605上的残差谓词和IX_PanelCdCl_PanelCdClStatusId中的一个索引范围扫描,只要{{1} }}

然而,他们不会扫描整个表/索引。查询在查询计划中从左到右执行,其中PanelCdClStatusId is null一次要求一行,直到不再有行为止。这意味着当顶级运算符具有所需的5000行时,它将停止从合并连接中请求新行。