OFFSET-FETCH 分页在数据量超10万行后性能急剧下降,因OFFSET需全扫描前N行;应改用键集分页(如WHERE created_at
直接说结论:用
OFFSET-FETCH写分页在数据量超过 10 万行后就会明显变慢,尤其翻到第 1000 页之后,逻辑读暴增、tempdb 溢出、响应时间跳到秒级——这不是 SQL 写得不对,是它底层机制决定的。真要处理大批量数据,得换思路,不是调参数能救的。为什么 OFFSET-FETCH 在大数据量下越往后越慢
因为
OFFSET 10000 ROWS不是“跳到第 10001 行”,而是让 SQL Server 从头开始逐行扫描、计数、跳过前 10001 行,再取下一批。哪怕你只想要 20 条,它也得把前面所有行都过一遍。
- 排序字段没索引?直接全表扫描 + Sort 算子溢出到 tempdb
- ORDER BY 里用了
LEFT JOIN后的字段(比如u.name),该字段可能为 NULL,导致排序不稳定,OFFSET可能漏行或重复- WHERE 条件没覆盖索引,或者用了函数(如
YEAR(created_at)),索引失效,性能雪崩用键集分页(Keyset Pagination)替代 OFFSET-FETCH
核心是放弃“第 N 页”这种基于偏移量的思维,改用“从上次最后一条记录的主键/时间戳继续往后查”。它不依赖行号,只靠索引定位,查询复杂度接近 O(log N)。
- 必须确保分页字段有高效索引,例如按
created_at DESC, id DESC排序,就建CREATE INDEX IX_orders_created_id ON orders(created_at DESC, id DESC)- 避免用
NOT IN或子查询做游标判断,比如WHERE id NOT IN (SELECT TOP 1000 id...),大数据下子查询会退化成全表扫描- 推荐写法是:每次查
WHERE created_at ,配合复合索引可走 Seek- 前端需传回上一页最后一条的
created_at和id,不能只传页码——这是键集分页的契约,绕不开存储过程中怎么安全拼接动态排序和条件
排序字段、表名、WHERE 条件如果来自参数,不用
QUOTENAME()包裹就是 SQL 注入温床,哪怕只给内部系统用也不保险。
- 表名、列名必须用
QUOTENAME(@TableName)和QUOTENAME(@SortField),否则传入orders; DROP TABLE orders--就完蛋- WHERE 条件字符串建议统一拼在变量里,比如
SET @where = 'status = 1 AND amount > 100',然后分页查询和COUNT(*)都复用它,避免两边条件不一致导致总数和数据对不上- 别用
COUNT(*) OVER()想“一次查出总数+数据”,执行计划仍要扫全表+加窗口聚合,比分开查还重- 如果业务允许弱一致性(如后台报表),可在查询中加
WITH (NOLOCK),但得清楚脏读风险——比如刚插入又被回滚的订单可能短暂出现在列表里总条数要不要每次都算?
要,但得控制代价。对千万级表执行
SELECT COUNT(*)是个阻塞操作,尤其并发高时容易拖垮整个库。
- 硬限制最大可查页码,比如
IF @PageIndex > 500 BEGIN RAISERROR('Page too deep', 16, 1) RETURN END,防恶意或误操作触发深分页- 后台类场景可缓存总条数:用带时间戳的物化视图或定时任务更新统计表,查分页时只读缓存值,误差容忍几秒到几分钟
- 如果必须实时,且 WHERE 条件固定,可建带过滤的索引视图(Indexed View),让
COUNT(*)走索引查找而非扫描真正难的不是写出能跑的分页存储过程,而是判断什么时候该放弃“页码”这个概念——当用户翻到第 5000 页时,他大概率不是在找数据,是在测试你的系统底线。这时候返回“请用搜索或筛选”比返回空结果或超时更诚实。
相关文章
怎样在Oracle存储过程中安全读取操作系统本地文件?
怎样在SQL存储过程中快速比对两张异构表的结构差异
怎样在Oracle中安全授予用户ALTER SYSTEM权限以调整参数?
如何在MySQL自定义函数中有效防止SQL注入安全漏洞?
HTML 中多选下拉框提交时合并多个值为单个键值对的解决方案
相关标签:
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门AI工具
相关专题
数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。
4783
2023.10.12
SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。
971
2023.10.27
在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。
1249
2024.02.23
SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。
6801
2024.03.06
sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。
3503
2024.03.06
运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。
6780
2024.04.07
sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。
1270
2024.04.29
DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。
0
2026.11.05
热门下载
相关下载
精品课程
最新文章










