更正Partition + Order的SQL索引以删除SORT

时间:2014-02-26 04:13:44

标签: sql sql-server performance

我有一个SQL语句,我试图优化以删除排序运算符

SELECT *,ROW_NUMBER() OVER (
        PARTITION BY RuleInstanceId 
        ORDER BY [Timestamp] DESC
   ) AS rn
FROM RuleInstanceHistoricalMembership

我读过的所有内容(例如Optimizing SQL queries by removing Sort operator in Execution plan)都表明这是要添加的正确索引,但它似乎根本没有效果。

CREATE NONCLUSTERED INDEX IX_MyIndex ON dbo.[RuleInstanceHistoricalMembership](RuleInstanceId, [Timestamp] DESC)

enter image description here

我必须遗漏一些东西,因为我已阅读大量文章,似乎都认为跨越两个专栏的索引应解决此问题

1 个答案:

答案 0 :(得分:9)

从技术上讲,您添加的索引可以避免排序。

但是,您创建的索引是非覆盖的,因此SQL Server还需要执行6000万次密钥查找回基表。

简单地扫描聚集索引并在运行中对其进行排序的成本比该选项便宜得多。

为了让索引自动使用,你需要。

  • 从查询SELECT列表中删除列,以便索引覆盖它。
  • INCLUDE - d列添加到索引。
BTW:对于一个包含6000万行的表,您可能会发现,即使您尝试使用非覆盖索引上的索引提示来强制解决问题,您仍然无法获得避免排序的预期结果。

CREATE TABLE RuleInstanceHistoricalMembership
  (
     ID             INT PRIMARY KEY,
     Col2           INT,
     Col3           INT,
     RuleInstanceId INT,
     [Timestamp]    INT
  )

CREATE NONCLUSTERED INDEX IX_MyIndex
  ON dbo.[RuleInstanceHistoricalMembership](RuleInstanceId, [Timestamp] DESC)

/*Fake small table*/
UPDATE STATISTICS RuleInstanceHistoricalMembership 
                  WITH ROWCOUNT = 600, 
                       PAGECOUNT = 10 

SELECT *,
       ROW_NUMBER() OVER ( PARTITION BY RuleInstanceId 
                               ORDER BY [Timestamp] DESC ) AS rn
FROM   RuleInstanceHistoricalMembership WITH (INDEX = IX_MyIndex) 

提供计划

enter image description here

除了行数和页数之外没有排序

/*Fake large table*/
UPDATE STATISTICS RuleInstanceHistoricalMembership 
                  WITH ROWCOUNT = 60000000, 
                       PAGECOUNT = 10000000 

再试一次,你得到了

enter image description here

现在它有两种类型!

NCI上的扫描按RuleInstanceId, Timestamp DESC顺序排列,然后SQL Server按Optimizing I/O Performance by Sorting重新排序为聚簇索引键顺序(Id ASC)。

此步骤旨在尝试将预期的6000万随机查找的大量成本降低到聚集索引中。然后它会重新排序回索引传递的原始RuleInstanceId, Timestamp DESC顺序。