数据库非聚集索引扫描而不是搜索

时间:2021-04-06 13:53:11

标签: sql-server

给定

SELECT 
    a.Id, a.Col1, b.Col1
FROM 
    Table1 a 
INNER JOIN 
    Table2 b ON a.Id = b.A_Id
WHERE
    b.Col1 = 'Val1'
    AND a.Col3 = 'Val3'
    AND a.Col4 = 'Val4'

以及表 1 和表 2 上的非聚集索引

CREATE NONCLUSTERED INDEX IX_Table1 ON Table1(Id ASC, Col3 ASC, Col4 ASC)

CREATE NONCLUSTERED INDEX IX_Table2 ON Table2(Col1 ASC, A_Id ASC)

上述查询对 IX_Table1 进行了索引扫描。

a.Id 是具有聚集索引的 PK,A_Ida.Id 的 FK。

顾问提议在 Table1 (Col1, Col2) 上建立索引。

我猜优化器是否能够在 IX_Table1 上进行索引搜索(而不是扫描),advisor 会很好。

有人可以帮忙弄清楚细节吗?

我看到在计划中,我们首先通过 Table1 中的谓词和 Key Lookup for Id 过滤掉?然后在 Table2 中搜索 Col1。

它不能首先使用 IX_Table1 进行 JOIN,然后通过索引中剩余的 Col3 和 Col4 过滤掉吗?

enter image description here

1 个答案:

答案 0 :(得分:1)

我将使用我在此处的评论中使用的相同类比,因为在我看来,电话簿的想法非常有效。

在这个例子中,让我们说 ID 是姓氏(我意识到电话簿中有这样的欺骗),Col1 是名字,Col3 是中间名首字母。我们暂时将忽略另一张桌子。我们订购的电话簿也按此顺序排列;首先是姓氏,然后是名字,最后是中间名首字母。

在您的查询中,您要查询名字和中间名首字母具有特定值的行。因此,您的索引在这里对您没有帮助;无论如何都无法快速找到您想要的人。您的所有数据都按姓氏的顺序排列,这意味着您将(单独)访问每个姓氏,然后查找名字,并过滤到该数据。因此,对于数据库引擎来说,检查每个值的速度可能一样快。

现在,让我们在这个类比中添加另一个表。这也是一个姓氏列表,其中也包含此人的性别认同。你也被要求只接待女性。然而,这有一个索引,首先按性别列出所有人,然后是姓氏。伟大的!您可以从那里快速获取所有女性的姓氏,并以此过滤您的电话簿数据,因为它也是按姓氏顺序排列的。

但是现在你还是有同样的问题;所有这些数据仍然按姓氏顺序排列,因此您找不到名字和中间名首字母符合您要求的人。因此,您必须再次扫描整个索引。

结果,是的,RDBMS 是正确的;这里 INDEXCol1 上的 Col3,没有 ID(因为它是 CLUSTERED INDEX,所以已经包含)正是您需要能够按“名字”顺序对数据进行排序。