导读:本期聚焦于小诸葛创作的《mysql如何进行分页查询?这几种方法及优化技巧你必须掌握》,敬请观看详情。LIMIT语句用起来很简单,为什么数据量一大查询就变得飞快又突然卡住?分页到几十万页时MySQL为什么要先扫完前面所有行才返回结果?本文从LIMIT offset的基本原理讲起,分析深分页性能急剧下降的根本原因,并给出覆盖索引、延迟关联、子查询定位、基于书签的游标分页等多种优化方案,同时对比各方案适用的业务场景,帮助你根据数据量和排序需求选择最合适的分页实现方式,让列表页在千万级数据下依然保持毫秒级响应。

做后台管理系统或者前端列表页,几乎都绕不开分页。MySQL里实现分页最常用的就是LIMIT加OFFSET的写法,比如LIMIT 10 OFFSET 20或者简写的LIMIT 20, 10。这条语句看似简单,但很多人在数据量涨到百万级之后会发现:前几页秒开,翻到几万页之后接口响应从几十毫秒飙到好几秒。要真正用好分页查询,需要理解LIMIT的工作机制,掌握深分页优化的常用手段。

mysql如何进行分页查询?这几种方法及优化技巧你必须掌握

一、LIMIT分页的基本用法与工作原理

先看最基础的写法。假设有一张用户表t_user,我们要查询第3页的数据,每页10条,SQL如下:

-- 写法一:LIMIT offset, count
SELECT id, name, created_at FROM t_user ORDER BY id LIMIT 20, 10;

-- 写法二:LIMIT count OFFSET offset,语义更直观
SELECT id, name, created_at FROM t_user ORDER BY id LIMIT 10 OFFSET 20;

这两种写法完全等价,都是跳过前20条,返回第21到第30条。注意OFFSET是从0开始的,所以第3页(每页10条)对应的偏移量是20,计算公式为offset = (page - 1) * pageSize

关键在于理解LIMIT背后发生了什么。当执行LIMIT 100000, 10时,MySQL并不是直接跳到第100001行,而是把前100010行都读取出来(如果在索引上遍历就是逐条回表),然后丢弃前100000行,只返回最后10行。也就是说,OFFSET越大,被浪费掉的扫描量越大,这就是深分页变慢的根本原因。扫描行数线性增长,响应时间也线性恶化,这是LIMIT分页先天无法回避的问题。

另外要注意,如果ORDER BY的列没有索引,MySQL还需要先对全表结果排序(可能是文件排序filesort),再截取分页片段,代价更高。所以无论用哪种分页方案,保证排序列上有合适的索引都是第一步。

二、深分页的四种优化方案

1. 子查询定位法:先找ID再回表

既然OFFSET慢在大量回表,可以先用覆盖索引只查主键,拿到目标起始ID后再关联回原表:

-- 优化前:100000次回表
SELECT id, name, created_at FROM t_user ORDER BY id LIMIT 100000, 10;

-- 优化后:子查询只在主键索引上定位,最后只回表10次
SELECT id, name, created_at FROM t_user
WHERE id >= (
    SELECT id FROM t_user ORDER BY id LIMIT 100000, 1
)
ORDER BY id LIMIT 10;

原理是子查询只扫描主键索引(覆盖索引,无需回表),定位到第100001条记录的主键值后,外层查询用WHERE id >=从该位置开始取10条。回表次数从十万级降到10次,提升非常明显。缺点是OFFSET部分的索引扫描依然存在,只是扫描代价大幅降低,极限深分页时仍会变慢。

2. 延迟关联:JOIN写法效果相同

SELECT t.id, t.name, t.created_at
FROM t_user t
INNER JOIN (
    SELECT id FROM t_user ORDER BY id LIMIT 100000, 10
) tmp ON t.id = tmp.id;

这和子查询定位法本质相同,都是利用覆盖索引减少回表。子查询在索引上完成分页截取,JOIN阶段只对最终的10条记录回表取字段。如果SELECT的列较多(比如文章表要取大字段content),延迟关联的收益会更明显。实际测试中,百万级表深分页通常能把耗时从秒级压到几十毫秒。

3. 覆盖索引:让分页完全走索引

如果查询需要的列都能放进一个联合索引,MySQL可以直接在索引上完成整条查询,完全避免回表:

-- 建联合索引,包含查询所需的所有列
ALTER TABLE t_user ADD INDEX idx_created_id_name (created_at, id, name);

-- 该查询全程走索引,不再回表
SELECT id, name, created_at FROM t_user
ORDER BY created_at, id LIMIT 100000, 10;

注意索引列的顺序要和ORDER BY一致,否则索引用不上排序还得额外filesort。这种方式的局限是索引不能包含太长的列(如TEXT大字段),且索引变宽会影响写入性能和空间占用,适合查询列较少的固定场景。

4. 游标分页(书签法):从根本上消灭OFFSET

如果业务允许,最推荐的方式是不用OFFSET,而是记住上一页最后一条记录的位置,下一页直接从它之后取:

-- 第一页
SELECT id, name, created_at FROM t_user ORDER BY id DESC LIMIT 10;

-- 下一页:以上一页最后一条的id作为游标
SELECT id, name, created_at FROM t_user
WHERE id < #{lastId}
ORDER BY id DESC LIMIT 10;

这种写法每一页都是WHERE id < 某个值 LIMIT 10,走索引范围定位,无论翻到第几页耗时都恒定在毫秒级,彻底解决了深分页问题。抖音、微博这类信息流的下拉加载基本都是这个方案。

它的代价是:不能直接跳转到任意页,只能连续翻页;排序字段必须唯一且单调(通常是主键或加上次级排序字段保证唯一),否则可能漏数据或重复。对于普通的后台管理列表,用户确实有跳页需求时,通常把游标分页留给前端无限滚动场景,后台仍用延迟关联兜底。

三、分页方案的选择与常见坑

方案没有绝对的好坏,按场景选择即可。下面这张表总结了各方案的适用情况:

方案性能是否支持跳页适用场景
LIMIT offset深分页差支持数据量小(十万以内)
子查询定位/延迟关联较好支持后台管理列表,数据量大且有跳页需求
覆盖索引支持查询列少且固定
游标分页恒定优秀不支持信息流、下拉加载

除了选型,还有几个常见的坑值得注意。第一,ORDER BY不加唯一字段可能导致分页数据重复或丢失,比如按created_at排序时同一秒有多条记录,不同页之间可能出现同一条记录。稳妥的写法是加上一个唯一列做次级排序:ORDER BY created_at, id

第二,统计总条数的COUNT(*)在大表上本身就很慢,MyISAM有缓存尚可,InnoDB的COUNT需要扫描。如果分页组件只用来展示"上一页/下一页",可以完全不查总数;如果必须显示总数,可以考虑单独维护计数字段、用Redis缓存,或者用EXPLAIN的估算行数做近似展示。

第三,记得用EXPLAIN验证执行计划,确认分页查询确实走了索引,关键看Extra列是否出现Using index(覆盖索引)以及rows估算值是否合理。如果发现filesort或者全表扫描,先检查排序列上的索引再谈其他优化。

总结一下:小数据量直接LIMIT就够了;数据量大且要跳页,用延迟关联或子查询定位;能改造产品形态接受连续翻页,就上游标分页,这是唯一能做到翻页性能与页码无关的方案。理解OFFSET的扫描机制,比记住任何一条优化SQL都更重要。

mysql分页查询LIMIT优化深分页修改时间:2026-09-04 13:14:40

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260904/50255.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。