使用日期索引优化 ROW_NUMBER()

Pet*_*ter 3 t-sql

我有这个简单的查询,希望它是不言自明的。

SELECT ROW_NUMBER() OVER (PARTITION BY Price_Id ORDER BY date DESC) r, *  FROM Samples
Run Code Online (Sandbox Code Playgroud)

我的问题是我有超过 80000 条记录,执行该查询需要大约 3 秒。我的问题是我是否可以做些什么来提高性能?

我在想一个索引,并想出了类似的东西

CREATE INDEX IX_Samples_Date ON Samples (Date DESC)
Run Code Online (Sandbox Code Playgroud)

但我不得不承认我以前从未使用过索引,而且我上面的尝试没有奏效。

Mik*_*son 5

你需要一个 POC 索引。查看SQL Server 2012索引指南部分:如何编写 T-SQL 窗口函数,第 3 部分

因此,在您的情况下,您需要将其Price_Id作为索引中的第一列。

create index IX_Samples_POC on dbo.Samples(Price_Id, date desc);
Run Code Online (Sandbox Code Playgroud)

但即使有索引,也不能保证 SQL Server 会使用它。您正在查询所有行和所有列,因此您可能会获得聚集索引扫描或表扫描,因为您的索引中可能没有包含所有其他列(聚集键是自动包含的)。

根据您的表结构的样子,如果您row_number在派生表中使用索引并将结果连接回您获取其余列的表,您可能会使用索引获得更快的计划。

假设您有一个主键 ID,它也是集群键,这样的事情。

select S.*,
       T.r
from Samples as S
  inner join (
             select ID,
                    row_number() over(partition by Price_Id 
                                        order by date desc) as r
             from dbo.Samples
             ) as T
    on S.ID = T.ID;
Run Code Online (Sandbox Code Playgroud)

另一种选择是在索引中包含您需要的列。如果您确实需要所有列,这可能不是一个好主意。

create index IX_Samples_POC on dbo.Samples(Price_Id, date desc) 
  include(Col1, Col2);
Run Code Online (Sandbox Code Playgroud)

覆盖索引与根本不使用索引之间的主要区别在于 SQL Server 必须对行进行排序才能枚举它们。索引已经提供了这种排序。