首页 > 解决方案 > 加速分区 ROW_NUMBER()

问题描述

我目前有这个查询(SQL Server):

DECLARE @PageNum int = 1;
DECLARE @PageSize int = 2;
SELECT *
FROM (
  SELECT *,ROW_NUMBER() OVER(PARTITION BY Color ORDER BY Name) AS Row
  FROM Orders
) t1
WHERE Row BETWEEN ((@PageNum-1)*@PageSize+1) AND (@PageNum*@PageSize)
ORDER BY Color,Name

这个查询的作用是它为每个选择带有 2 条记录的“页面” Color。意思是如果表包含:

ID 颜色 姓名
1 红色的 论文#1
2 红色的 论文#2
3 红色的 论文#3
4 绿 论文#4
5 绿 论文#5
6 绿 论文#6
7 绿 论文#7

那么上面的查询将导致:

ID 颜色 姓名
1 红色的 论文#1
2 红色的 论文#2
4 绿 论文#4
5 绿 论文#5

在第 1 页和

ID 颜色 姓名
3 红色的 论文#3
6 绿 论文#6
7 绿 论文#7

在第 2 页。

这行得通。但是,在我的实际示例中,此查询需要很长时间才能执行——实际上大约需要 10 分钟。我有一个包含超过 80 万条记录的静态表,这些记录永远不会改变。由于该表永远不会更改,因此我为要过滤/排序的每一列创建了一个索引。该表还有一个 column RowId,实际上只是行号,并且它具有唯一索引。

执行计划可以在这里看到:https ://www.brentozar.com/pastetheplan/?id=BkeWfVCSY

我能做些什么来加快这个查询?

标签: sqlsql-servertsql

解决方案


您的执行计划中的第一个操作是表扫描,所以我假设这是一个堆表(否则我们应该看到聚集索引扫描)并且您创建的索引没有被使用。

此外,一旦这是一个永远不会改变的静态表,根据描述,碎片应该不是问题。

我没有在这台机器上安装 SQL Server,所以我无法比较之前和之后的执行计划,但我相信对于您的查询,我们可能会看到聚集索引的一些改进,按照 Martin Smith 的建议对键进行排序他的评论。

CREATE CLUSTERED INDEX IX_Order ON dbo.Order(OrderType ASC, From DESC)

请让我知道这是否可以改善您的查询。如果没有,我可以创建一个类似的场景在白天进行测试。


推荐阅读