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

时间:2016-08-24 10:59:37

标签: sql sql-server sql-server-2014 database-performance query-performance

  

可能的解释是in the comment

在SQL Server 2014 Enterprise Edition(64位)中 - 我试图从View中读取。标准查询只包含ORDER BYOFFSET-FETCH这样的子句。

方法1

SELECT

    *

FROM Metadata
ORDER BY
    AgeInHours      ASC, 
    RankingPoint    DESC, 
    PublishDate     DESC
OFFSET 150000 ROWS
FETCH NEXT 40 ROWS ONLY

然而,这个相当简单的查询执行几乎 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

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

(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.

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

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

模式

Schema

方法1:执行计划

Approach 1: Execution Plan

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

Approach 2: Execution Plan (Left part)

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

Approach 2: Execution Plan (Right part)

2 个答案:

答案 0 :(得分:1)

对于具有相同结果集的不同结构化查询,您将获得具有不同方法和查询成本的不同查询计划。这在各种SQL RDBMS实现中很常见。

基本上在上面的示例中,从大表中选择一小部分数据时,首先要减少和最小化结果中的行数,然后选择所有列的完整行,就像2.查询一样。

另一种方法是在第一步中为减少结果集建立精确的正确索引。在上面的查询中,ORDER BY子句中的列可能只是一个解决方案。

(您没有发送查询计划中提到的索引结构,我可以想象隐藏在其名称后面的内容。)

您还可以使用SQL索引提示将SQL优化器定向到您认为最适合任务的特定索引,以防SQL优化器无法执行此任务。

答案 1 :(得分:0)

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

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

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