SQL 深分页的典型优化方案
发布时间 - 2026-01-25 00:00:00 点击率:次OFFSET N LIMIT M 深分页变慢是因为数据库必须扫描并跳过前N行,I/O和CPU成本随OFFSET线性增长;应优先采用游标分页、覆盖索引+延迟关联或预生成映射表等优化方案。
为什么 OFFSET N LIMIT M 在深分页时变慢
因为数据库必须扫描并跳过前 N 行,哪怕你只想要第 100 万页的 20 条数据。InnoDB 的聚簇索引顺序读 + 逐行计数机制决定了这个过程无法跳过中间数据,I/O 和 CPU 成本随 OFFSET 线性增长。
常见现象包括:查询响应从几毫秒飙升到数秒、执行计划中 type 变为 ALL 或 index、Extra 出现 Using filesort 或 Using temporary。
- 即使有
created_at索引,ORDER BY created_at LIMIT 1000000, 20仍需定位到第 1000001 行物理位置 -
COUNT(*)全表统计 +OFFSET混用会触发双重全扫 - MySQL 8.0+ 的
SKIP LOCKED对深分页无加速作用,它只解决并发更新冲突
用游标分页(Cursor-based Pagination)替代 OFFSET
核心是利用排序字段的**唯一性 + 单调性**,把“我要第 N 页”转成“从上一页最后一条记录之后开始取”。要求排序字段(如 id 或 created_at)有索引且尽量避免重复值。
示例:假设按 id 降序分页,上一页最后一条是 id = 5000000,下一页查询写成:
SELECT *FROM orders WHERE id < 5000000 ORDER BY id DESC LIMIT 20;
- 必须确保
id是主键或有唯一索引,否则可能漏数据或重复 - 若排序字段非唯一(如
status),需组合二级条件去重:WHERE (created_at, id) - 前端需保存上一页末尾的完整游标值,不能只传页码——这是最容易被忽略的协作点
覆盖索引 + 延迟关联减少回表
当必须用 OFFSET(比如管理后台支持跳转任意页),优先让 WHERE 和 ORDER BY 走覆盖索引,再用主键回查详情,避免大范围全字段扫描。
例如查询用户订单列表,只展示 order_id、user_id、amount、created_at:
SELECT t1.order_id, t1.user_id, t1.amount, t1.created_at
FROM orders t1
INNER JOIN (
SELECT id FROM orders
WHERE status = 'paid'
ORDER BY created_at DESC
LIMIT 1000000, 20
) t2 ON t1.id = t2.id;- 子查询只查
id(主键),走status + created_at联合索引即可完成排序和偏移 - 外层用
JOIN回查,比直接SELECT *少读大量非索引列 - 注意 MySQL 5.7 中子查询 LIMIT 不走索引优化,建议升级到 8.0+ 或改用物化 CTE
预生成分页映射表或使用 ES 同步
对实时性要求不高的场景(如后台报表、历史归档),可把分页位置固化下来。本质是用空间换时间,规避每次计算偏移量。
- 建一张
page_offset_map表,每 1000 条存一条记录:page_no、min_id、max_id、total_count,定时任务维护 - 搜索类分页直接交给 Elasticsearch,用
search_after实现游标分页,性能远超 MySQL 原生方案 - 不要在 MySQL 里用
SELECT COUNT(*)动态算总页数——加个WHERE条件后误差可能极大,前端显示 “共 50000 页” 本身就不准确
游标分页不是银弹:它不支持跳转任意页、无法获取总条数、对排序字段稳定性要求高。真正要落地,得先理清业务是否真的需要“第 N 页”这个概念——很多时候只是 UI 设计惯性而已。
# mysql
# 前端
# ai
# 为什么
# sql
# count
# select
# using
# 并发
# elasticsearch
# 数据库
# ui
# 分页
# 上一页
# 跳过
# 主键
# 跳转
# 变慢
# 性要求
# 这是
# 我要
# 是因为
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
网站页面设计需要考虑到这些问题
非常酷的网站设计制作软件,酷培ai教育官方网站?
Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程
,在苏州找工作,上哪个网站比较好?
如何彻底删除建站之星生成的Banner?
香港服务器租用每月最低只需15元?
Laravel如何实现文件上传和存储?(本地与S3配置)
详解MySQL数据库的安装与密码配置
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
如何快速完成中国万网建站详细流程?
绝密ChatGPT指令:手把手教你生成HR无法拒绝的求职信
动图在线制作网站有哪些,滑动动图图集怎么做?
长沙企业网站制作哪家好,长沙水业集团官方网站?
Laravel如何配置和使用缓存?(Redis代码示例)
Laravel怎么多语言本地化设置_Laravel语言包翻译与Locale动态切换【手册】
浅谈javascript alert和confirm的美化
如何用JavaScript实现文本编辑器_光标和选区怎么处理
Laravel如何实现模型的全局作用域?(Global Scope示例)
Laravel如何操作JSON类型的数据库字段?(Eloquent示例)
如何用景安虚拟主机手机版绑定域名建站?
Laravel如何实现API速率限制?(Rate Limiting教程)
Laravel怎么实现验证码(Captcha)功能
Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程
如何用PHP工具快速搭建高效网站?
JS弹性运动实现方法分析
html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】
Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性
如何用IIS7快速搭建并优化网站站点?
LinuxShell函数封装方法_脚本复用设计思路【教程】
公司网站制作需要多少钱,找人做公司网站需要多少钱?
Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置
Laravel如何实现用户注册和登录?(Auth脚手架指南)
黑客入侵网站服务器的常见手法有哪些?
今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】
文字头像制作网站推荐软件,醒图能自动配文字吗?
Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全
Android实现代码画虚线边框背景效果
PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)
香港网站服务器数量如何影响SEO优化效果?
如何在Windows环境下新建FTP站点并设置权限?
Laravel如何实现API版本控制_Laravel版本化API设计方案
Laravel怎么导出Excel文件_Laravel Excel插件使用教程
html5如何设置样式_HTML5样式设置方法与CSS应用技巧【教程】
javascript基于原型链的继承及call和apply函数用法分析
Laravel如何使用Spatie Media Library_Laravel图片上传管理与缩略图生成【步骤】
Laravel如何记录日志_Laravel Logging系统配置与自定义日志通道
如何利用DOS批处理实现定时关机操作详解
Laravel怎么做缓存_Laravel Cache系统提升应用速度的策略与技巧
Laravel如何实现API版本控制_Laravel API版本化路由设计策略
Laravel如何处理文件下载请求?(Response示例)


