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

Not*_*ple 10 sql sql-server performance

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

SELECT *,ROW_NUMBER() OVER (
        PARTITION BY RuleInstanceId 
        ORDER BY [Timestamp] DESC
   ) AS rn
FROM RuleInstanceHistoricalMembership
Run Code Online (Sandbox Code Playgroud)

我读过的所有内容(例如,通过删除执行计划中的排序运算符来优化SQL查询)表明这是要添加的正确索引,但它似乎完全没有效果.

CREATE NONCLUSTERED INDEX IX_MyIndex ON dbo.[RuleInstanceHistoricalMembership](RuleInstanceId, [Timestamp] DESC)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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

Mar*_*ith 10

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

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

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

为了使索引自动使用,您需要.

  • 从查询SELECT列表中删除列,以便索引覆盖它.
  • INCLUDE向索引添加-d列.

顺便说一句:对于一个有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) 
Run Code Online (Sandbox Code Playgroud)

给出了计划

在此输入图像描述

没有排序,但行和页数

/*Fake large table*/
UPDATE STATISTICS RuleInstanceHistoricalMembership 
                  WITH ROWCOUNT = 60000000, 
                       PAGECOUNT = 10000000 
Run Code Online (Sandbox Code Playgroud)

然后再试一次,你得到

在此输入图像描述

现在它有两种!

NCI上的扫描是按RuleInstanceId, Timestamp DESC顺序进行的,但随后SQL Server将其重新排序为聚合索引键顺序(Id ASC),以通过排序优化I/O性能.

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