可能的解释是in the comment
在SQL Server 2014 Enterprise Edition(64位)中 - 我试图从View中读取。标准查询只包含ORDER BY
和OFFSET-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上测试了这个。
有人可以解释发生了什么吗?
模式
方法1:执行计划
方法2:执行计划(左侧部分)
方法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,或者如果有数百万行则使用索引创建临时表,则甚至可以获得更好的性能。