索引定义顺序和 ORDER BY 子句

Dou*_*ats 5 index sql-server order-by

所以我早上正在阅读博客,偶然发现了这个有趣的练习:

https://www.erikdarlingdata.com/sql-server/lets-design-an-index-together-part-3/

这是文章中的相关查询和他建议的索引。

SELECT TOP (5000)
       p.LastActivityDate,
       p.PostTypeId,
       p.Score,
       p.ViewCount
FROM dbo.Posts AS p
WHERE p.PostTypeId = 1
AND   p.LastActivityDate >= '20110101'
ORDER BY p.Score DESC;

CREATE INDEX whatever 
    ON dbo.Posts(PostTypeId, Score DESC, LastActivityDate) 
        INCLUDE(ViewCount) WITH (DROP_EXISTING = ON);
Run Code Online (Sandbox Code Playgroud)

非常有趣的构建和索引,并尝试相应地调整它。但是,我之前可能存在误解,认为索引键顺序很重要,并且当索引键顺序与查询不匹配时,某些 WHERE 子句可能不会使用某些索引。这意味着,我缺乏列出的特定场景的经验,我假设的想法是该查询不会使用该索引,因为 Score 位于索引键定义的中间,但不在查询的 where 子句中。

当优化器决定使用哪个索引时,ORDER BY 列是否会被评估,并且只要 WHERE 子句列和 ORDER by 列在索引定义中,那么它就会使用它?

我想我的问题更多是关于优化器如何评估 WHERE 子句和 ORDER BY 子句的索引。

Rob*_*ley 7

键的顺序绝对很重要。两个建议的索引采用不同的方法来解决这个问题。

\n

让\xe2\x80\x99s 考虑一下索引打开时查询如何运行(PostTypeID, LastActivityDate),考虑手动执行。

\n

我们可以很容易地找到与 WHERE 子句匹配的所有行 - PostTypeID 1 且足够新。但随后我们需要按 Score 排序以找到前 5000 行。如果我们有很多行要排序,这可能会很昂贵。

\n

或者,使用索引(PostTypeID, Score DESC),我们只能过滤到 PostTypeID,但随后我们可以按正确的顺序浏览该数据。是的,我们必须根据 LastActivityDate 拒绝任何不够新的行,但是一旦我们找到了我们关心的 5000 行,我们就可以停止了。我们不必进行这种昂贵的排序。但我们\xe2\x80\x99 正在查找的行数超出了我们关心的行数。顺便说一句,我不认为 \xe2\x80\x99 在关键列中包含 LastActivityDate 有多大价值 - 它会很好地适合包含的列,因为 \xe2\x80\x99s 不播放Seek 谓词中的一部分。Seek 运算符只是按 Score 顺序返回该 PostTypeID 值的所有行。

\n

查询优化器知道可以按照索引中指定的顺序从索引中提取数据,这可以在很多方面使其受益。也许它对合并连接、流聚合或 ORDER BY 子句有帮助。

\n

如果我们认为 PostTypeID 被过滤为单个值,则一个索引位于 Score 上以避免排序,而另一个索引位于 LastActivityDate 上以收紧搜索范围。QO 权衡每一项的预期成本并选择 \xe2\x80\x98cheaper\xe2\x80\x99 之一。

\n