MySQL分页查询怎么写才高效?深度分页优化方案全解析

来源:站长论坛作者:南京GEO公司头衔:草根站长
导读:本期聚焦于南京GEO公司创作的《MySQL分页查询怎么写才高效?深度分页优化方案全解析》,敬请观看详情。分页功能几乎是每个业务系统都绕不开的需求,但很多人写出来的分页SQL在数据量一大之后就变得极慢。一句简单的limit 100000,20为什么动辄耗时好几秒?本文从MySQL的存储引擎执行机制入手,分析limit偏移量分页慢的根本原因,并给出覆盖索引、延迟关联、子查询定位、书签方式等多种优化写法,同时附上各方案的性能对比和适用场景说明,帮助你根据实际数据规模选择合适的分页策略。

分页是业务系统里最常见的需求之一,列表页、订单查询、后台管理系统都离不开它。表面上写一条limit语句就能搞定,可一旦表里的数据涨到几十万、上百万行,原本毫秒级的查询可能突然变成好几秒。问题的根源不在limit本身,而在于我们使用limit的方式。这篇文章就来把MySQL分页的底层逻辑讲清楚,并给出几种经过实践检验的高效写法。

MySQL分页查询怎么写才高效?深度分页优化方案全解析

一、limit偏移量分页为什么越翻越慢

最常见的分页写法是SELECT * FROM orders ORDER BY id LIMIT 100000, 20。这条语句的语义是跳过前100000行,返回之后的20行。MySQL并没有办法直接定位到第100001行,它的做法是:沿着排序结果依次扫描,把前面100000行都取出来丢弃,只保留最后20行。

也就是说,偏移量越大,需要扫描和丢弃的行数就越多,耗时自然线性增长。当用户翻到第一万页时,数据库实际上做了大量无用功。此外,如果排序字段上没有索引,还会触发文件排序(filesort),性能进一步恶化。可以通过EXPLAIN观察执行计划,出现Using filesort就是一个明显信号。

另一个容易被忽视的点是SELECT *。即便二级索引上已经排好了序,回表取全部字段的开销依然存在。扫描十万行就要回表十万次,这是深度分页慢的第二大元凶。

二、覆盖索引与延迟关联优化

第一种优化思路是减少回表次数,典型写法叫延迟关联:先用子查询在索引上定位到目标行的主键,再用主键回表取完整数据。

-- 原始写法,深度分页时很慢
SELECT * FROM orders ORDER BY id LIMIT 100000, 20;

-- 延迟关联:先在索引上拿到主键,再回表
SELECT t.* FROM orders t
INNER JOIN (
    SELECT id FROM orders ORDER BY id LIMIT 100000, 20
) tmp ON t.id = tmp.id;

这条改写为什么有效?关键在于子查询里的SELECT id。如果id本身就是主键,或者存在一个只包含排序字段的二级索引,那么子查询可以完全在索引上完成,不回表。扫完100020个索引条目后只对最终选出的20行做回表,磁盘IO大幅下降。

实测数据可以说明差距:在500万行的表上,直接limit 4000000,20大约需要3秒,而延迟关联写法通常能降到0.5秒以内。提升幅度取决于行宽,行越宽(字段越多、大字段越多),延迟关联的收益越明显。

三、书签方式:记住上次的位置

延迟关联虽然有效,但本质上还是要扫过所有被跳过的索引条目。如果业务允许,有一种更彻底的方案:不传页码,改传上一页最后一条记录的排序值,这就是所谓的书签分页或游标分页。

-- 第一页
SELECT * FROM orders ORDER BY id DESC LIMIT 20;

-- 下一页:记住上一页最后的id
SELECT * FROM orders WHERE id < 100981 ORDER BY id DESC LIMIT 20;

这种写法利用索引直接定位到起点,扫描的行数永远只有20行,无论翻到第几页耗时都恒定,时间复杂度是O(1)级别的。像朋友圈、微博时间线这类无限下拉的场景,用的就是这种方案。

书签方式的局限是只能顺序翻页,不能直接跳到第N页,而且排序字段如果有重复值,需要额外的字段组合来保证游标唯一,比如WHERE create_time < ? OR (create_time = ? AND id < ?)。对于后台管理这类必须支持跳页的场景,可以折中处理:前几页用limit,深页用延迟关联,或者干脆限制最大可访问页数。

四、其他辅助手段与选型建议

除了SQL层面的改写,还有一些配套措施值得做。首先是索引设计,排序字段和过滤条件要尽量组合成联合索引,让WHERE条件和ORDER BY都能走索引,避免filesort。其次,如果总量不需要精确,可以避免每次都执行COUNT(*)统计总数,改用估算值或者缓存结果。

对于数据量特别大的冷数据分页,还可以考虑把历史数据归档到单独的表或者搜索引擎(如Elasticsearch)中,主表只保留活跃数据,分页压力自然就小了。

选型上可以简单总结:中小数据量直接limit没问题;需要跳页的深度分页用延迟关联;App端的瀑布流场景优先书签分页;千万级以上的复杂检索交给搜索引擎。没有万能写法,理解每种方案背后的IO模型,才能对症下药。

五、总结

MySQL深度分页慢的本质是偏移量扫描加回表的双重开销。覆盖索引和延迟关联解决的是回表问题,书签分页解决的是重复扫描问题,索引优化解决的是排序问题。写分页SQL时养成看执行计划的习惯,关注扫描行数这个指标,比单纯记写法更有价值。把这几招用到位,百万级数据的分页查询稳定在百毫秒以内并不是难事。

MySQL分页深度分页优化limit优化修改时间:2026-09-16 11:06:44

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