给定
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_Id
是 a.Id
的 FK。
顾问提议在 Table1 (Col1, Col2)
上建立索引。
我猜优化器是否能够在 IX_Table1
上进行索引搜索(而不是扫描),advisor 会很好。
有人可以帮忙弄清楚细节吗?
我看到在计划中,我们首先通过 Table1 中的谓词和 Key Lookup for Id 过滤掉?然后在 Table2 中搜索 Col1。
它不能首先使用 IX_Table1
进行 JOIN,然后通过索引中剩余的 Col3 和 Col4 过滤掉吗?
答案 0 :(得分:1)
我将使用我在此处的评论中使用的相同类比,因为在我看来,电话簿的想法非常有效。
在这个例子中,让我们说 ID
是姓氏(我意识到电话簿中有这样的欺骗),Col1
是名字,Col3
是中间名首字母。我们暂时将忽略另一张桌子。我们订购的电话簿也按此顺序排列;首先是姓氏,然后是名字,最后是中间名首字母。
在您的查询中,您要查询名字和中间名首字母具有特定值的行。因此,您的索引在这里对您没有帮助;无论如何都无法快速找到您想要的人。您的所有数据都按姓氏的顺序排列,这意味着您将(单独)访问每个姓氏,然后查找名字,并过滤到该数据。因此,对于数据库引擎来说,检查每个值的速度可能一样快。
现在,让我们在这个类比中添加另一个表。这也是一个姓氏列表,其中也包含此人的性别认同。你也被要求只接待女性。然而,这有一个索引,首先按性别列出所有人,然后是姓氏。伟大的!您可以从那里快速获取所有女性的姓氏,并以此过滤您的电话簿数据,因为它也是按姓氏顺序排列的。
但是现在你还是有同样的问题;所有这些数据仍然按姓氏顺序排列,因此您找不到名字和中间名首字母符合您要求的人。因此,您必须再次扫描整个索引。
结果,是的,RDBMS 是正确的;这里 INDEX
和 Col1
上的 Col3
,没有 ID
(因为它是 CLUSTERED INDEX
,所以已经包含)正是您需要能够按“名字”顺序对数据进行排序。