sql - 使用分页优化 SQL 查询
问题描述
我有一个针对 SQL Server 数据库运行的查询,执行时间超过 10 秒。被查询的表有超过 1400 万行。
我想按给定的日期顺序显示表中的Text
列。可能有数千个条目,所以我想将返回的值限制在可管理的水平。Notes
ServiceUserId
SELECT Text
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY [DateDone]) AS RowNum, Text
FROM
Notes
WHERE
ServiceUserId = '6D33B91A-1C1D-4C99-998A-4A6B0CC0A6C2') AS RowConstrainedResult
WHERE
RowNum >= 40 AND RowNum < 60
ORDER BY
RowNum
以下是上述查询的执行计划。
- 非聚集索引 -
ServiceUserId
和DateDone
列上的非聚集索引按升序排列。 - 键查找 - 表的主键
NoteId
如果我第二次运行相同的查询但使用不同的行号,那么我会以毫秒为单位得到响应,我假设来自缓存的执行计划。运行不同的查询ServiceUserId
将需要大约 10 秒。
有关如何加快此查询的任何建议?
解决方案
您应该查看 Keyset Pagination。
它比行集分页性能要好得多。
它与它根本不同,因为它不是引用特定的行号块,而是引用起始点来查找索引键。
它更快的原因是您不关心特定键之前有多少行,您只需寻找一个键并向前(或向后)移动。
假设您正在按单个ServiceUserId
排序,按DateDone
. 您需要一个如下索引(INCLUDE
如果它太大,您可以忽略它,它不会对数学产生太大影响):
create index IX_DateDone on Notes (ServiceUserId, DateDone) INCLUDE (TEXT);
现在,当您选择一些行时,不要给出开始和结束行号,而是给出起始键:
SELECT TOP (20)
Text,
DateDone
FROM
Notes
WHERE
ServiceUserId = '6D33B91A-1C1D-4C99-998A-4A6B0CC0A6C2'
AND DateDone > @startingDate
ORDER BY
DateDone;
在下一次运行中,您传递DateDone
您收到的最后一个值。这会让你获得下一批。
一个小缺点是你不能跳转页面。但是,用户想要跳转到第 327 页的情况比某些人想象的要少得多(从 UI 的角度来看)。所以这并不重要。
密钥必须是唯一的。如果它不是唯一的,则您无法精确地寻找下一行。如果您需要使用额外的列来保证唯一性,它会变得有点复杂:
WITH NotesFiltered AS
(
SELECT * FROM Notes
WHERE
ServiceUserId = '6D33B91A-1C1D-4C99-998A-4A6B0CC0A6C2'
)
SELECT TOP (20)
Text,
DateDone
FROM (
SELECT
Text,
DateDone,
0 AS ordering
FROM NotesFiltered
WHERE
DateDone = @startingDate AND NoteId > @startingNoteId
UNION ALL
SELECT
Text,
DateDone,
1 AS ordering
FROM NotesFiltered
WHERE
DateDone > @startingDate
) n
ORDER BY
ordering, DateDone, NoteId;
边注
在支持行值比较的 RDBMS 中,多列示例可以通过以下方式简化为原始代码:
WHERE (DateDone, NoteId) > (@startingDate, @startingNoteId)
不幸的是 SQL Server 目前不支持这个。
请为此投票支持Azure 反馈请求
推荐阅读
- javascript - 关闭和打开应用程序的实时服务器会删除我的本地存储
- jquery - 如何使用 jquery 在 display:none 和 display:flex 之间切换元素
- angular - 如何在更新数据源时保留 mat-table 行状态?
- java - 方法一步一步
- mysql - Laravel 如何为 hasMany 进行子查询/自定义关系查询
- python - 考虑到 X 和 Y 上的误差,在数据 X 和 Y 上拟合一条直线
- python - 在执行 pygame 项目的过程中使用 Python 的多处理
- java - 如何在 Java Swing 中找到最后按下的按钮
- docker - 由 Dockerfile 或 Docker-compose 文件创建的 Docker 卷
- reactjs - 反应,在选择选项上获取数据属性