SQL Server查询优化 - 简单查询中的意外缓慢

und*_*ned 9 sql sql-server database-performance query-performance sql-server-2014

可能的解释在评论中

在SQL Server 2014企业版(64位)中 - 我试图从视图中读取.标准查询只包含一个ORDER BY和这样的OFFSET-FETCH子句.

方法1

SELECT

    *

FROM Metadata
ORDER BY
    AgeInHours      ASC, 
    RankingPoint    DESC, 
    PublishDate     DESC
OFFSET 150000 ROWS
FETCH NEXT 40 ROWS ONLY
Run Code Online (Sandbox Code Playgroud)

但是,这个相当简单的查询比以下返回相同结果的查询执行快9倍(在跳过大量行(如150k)时显而易见).

在这种情况下,我首先读取主键,然后将其用作WHERE...IN函数的参数

方法2

SELECT 
    * 
FROM Metadata
WHERE NewsId IN (
    SELECT

        NewsId

    FROM Metadata
    ORDER BY
        AgeInHours      ASC, 
        RankingPoint    DESC, 
        PublishDate     DESC
    OFFSET 150000 ROWS
    FETCH NEXT 40 ROWS ONLY
)
ORDER BY
    AgeInHours      ASC, 
    RankingPoint    DESC, 
    PublishDate     DESC
Run Code Online (Sandbox Code Playgroud)

这两个基准标记显示了这种差异

(40 row(s) affected)

 SQL Server Execution Times:
   CPU time = 14748 ms,  elapsed time = 3329 ms.

(40 row(s) affected)

 SQL Server Execution Times:
   CPU time = 3828 ms,  elapsed time = 469 ms.
Run Code Online (Sandbox Code Playgroud)

我在主键上有索引,PubilshDate它们的碎片非常低.我还尝试对数据库表运行类似的查询,但在每种情况下,第二种方法都会产生很大的性能提升.我也在SQL Server 2012上测试了这个.

有人可以解释发生了什么吗?

架构

架构

方法1:执行计划

方法1:执行计划

方法2:执行计划(左侧部分)

方法2:执行计划(左侧部分)

方法2:执行计划(右侧部分)

方法2:执行计划(右侧部分)

小智 0

当您执行查询时,引擎会查找可用于获得最佳性能的索引。您的方法 1 是使用不包含 SELECT 语句中所有列的索引,这会导致查询计划中的键查找,根据我的经验,在 SELECT 语句中仅使用索引列总是会获得较低的性能。

如果为所有列创建索引AgeInHours, RankingPoint, PublishDate并包含所有列(建议仅用于测试目的),您可以看到差异。

对于第二种方法,如果您使用 CTE,然后使用 IN 进行 JOIN 而不是 WHERE,或者如果您有数百万行,则使用带有索引的临时表,您甚至可以获得更好的性能。