MySQL 分页查询怎么写:三种实现方式一次讲清

编程狮(w3cschool.cn) 2026-09-07 17:31:36 浏览数 (26)
反馈

你做了一个列表接口,前几页秒回,翻到第一百页却卡了好几秒——这不是数据变多了,而是你的分页写法在深分页时拖了后腿。核心答案一句话:最常用的是 LIMIT offset, size,但它翻得越深越慢;追求深分页性能要用"游标分页"(WHERE id > 上一页最后id ORDER BY id LIMIT size),让数据库跳过前面所有行直接定位。本文把三种写法一次讲清,重点说清 offset 过大时为什么变慢、keyset 怎么解决。编程狮用对比示例帮你选对写法。

MySQL 分页查询怎么写:三种实现方式一次讲清封面图

一、什么是 MySQL 分页查询

分页查询,就是把一份很大的结果集按"每页几条"切成一段段返回,前端一页一页翻。比如商品列表有十万条,你不可能一次全丢给浏览器,而是每次只取第 N 页的 20 条。MySQL 靠 LIMIT 子句实现这种"取一段"的能力。

打个比方:分页查询像翻书,你不会把整本书一次摊开,而是说"从第 80 页开始,读 20 页"。数据库也是,你告诉它"从第几个开始、取几个",它就只返那一段。

SELECT id, title FROM goods ORDER BY id LIMIT 20;

这条只取前 20 条。真正的分页查询要带上"起点",也就是 offset。起点越大,数据库要跳过前面的行就越多——这正是后面"深分页变慢"的根源,先在这里建立直觉。想系统学 SQL 查询,可以先过一遍 MySQL 教程 的 SELECT 与 LIMIT 章节,把结果集、排序、截断的概念弄顺,再看本文会轻松。

二、LIMIT offset,size 是最常用的分页写法

最常见的分页查询写法是 LIMIT offset, size:第一个数是"跳过几条",第二个数是"取几条"。比如 LIMIT 40, 20 表示跳过前 40 条、取接下来 20 条,对应第 3 页(每页 20 条)。

SELECT id, title FROM goods ORDER BY id LIMIT 40, 20;

这条返回第 3 页数据。offset 的计算公式是 (页码-1)*size。它写起来最短、最直觉,是绝大多数后台列表接口的第一版写法。注意 ORDER BY 不能省,否则"第几页"在不同查询里含义会变,结果会乱跳。

💡 小提示:永远给分页查询加稳定的 ORDER BY(最好用唯一列如 id),否则翻页时同一行可能重复出现或丢失。

三、LIMIT size OFFSET offset 标准写法

和上面等价、但更不容易读错的是 LIMIT size OFFSET offset:把"取几条"放前面、"跳过几条"用 OFFSET 显式写出。语义上更清晰,也更符合 SQL 标准语法,团队代码规范里常被要求统一用它。

SELECT id, title FROM goods ORDER BY id LIMIT 20 OFFSET 40;

这条和第二节完全等价,都是跳过 40 取 20。两种写法数据库执行一样,选哪种看团队习惯。但无论哪种,分页查询的"跳过"动作在深分页时都会成为性能隐患,下一节细说。想回查 LIMIT 与 OFFSET 的语法细节,MySQL 速查手册 能随时对照,避免把两个参数的顺序搞反。

四、深分页时 offset 过大为何变慢

问题出在 offset 的工作原理:它要先把前面 offset 行全部"扫一遍再丢弃",才轮到你要的那一段。翻到第 100 页、每页 20 条,offset 就是 1980,数据库得先读出并丢掉前 1980 行,只返最后 20 条——白干的活随页数线性增长。

深分页越深越慢,是因为偏移量越大、被扫描又丢弃的行越多。在数据量大、没命中索引覆盖时,这种"扫了不用"的成本直接体现在响应时间上,前几页毫秒级、第一百页好几秒就是这么来的。

-- 翻到第 100 页:数据库要先扫并丢弃前 1980 行
SELECT id, title FROM goods ORDER BY id LIMIT 1980, 20;

这条语句里 1980 行的偏移量就是性能杀手。它逻辑没错,但执行代价随页码飙升。理解这一点,你就知道治本不在"优化 LIMIT",而在"别让数据库去数前面那些没用的行"。

⚠️ 注意:深分页别指望加索引就能根治。索引能加速定位,但 offset 仍需跳过前面所有行,量级问题要靠换写法解决。

五、游标 keyset 分页解决深分页性能问题

游标分页(也叫 keyset 分页)的思路是:不告诉数据库"跳过多少行",而是告诉它"从上一页最后那条之后开始取"。利用索引的有序性,让 WHERE id > 上一页最后id 直接定位,跳过前面所有行。

游标分页把深分页的性能问题彻底化解,因为不再有 offset。数据库顺着 id 索引一路走到起点,只取你要的 size 条,无论翻到第几页都几乎是恒定开销。它要求结果按某个唯一且有序的列(通常主键 id)排序。

-- 上一页最后一条 id 是 1980,直接定位,不再扫描前面的行
SELECT id, title FROM goods
WHERE id > 1980
ORDER BY id
LIMIT 20;

这条用 WHERE id > 1980 取代偏移量,数据库借索引直达起点。keyset 分页的代价是不能"跳到第 N 页",只能"下一页下一页"翻,但列表流、无限滚动这类场景恰恰不需要跳页,反而更合适。MySQL 8 的窗口函数与索引优化可参考 MySQL8 教程 的相关章节。

💡 小提示:普通后台管理用 LIMIT offset 足够;对外的高并发列表、无限滚动优先上 keyset 分页,深分页性能差的问题会消失。

根据数据量与翻页深度选择分页方式的决策树

总结

MySQL 分页查询的本质是"取结果集的一段"。LIMIT offset, size 和 LIMIT size OFFSET offset 是同一件事的两种写法,最常用也最直觉;但 offset 越大、深分页越慢,因为数据库要扫了又丢弃前面所有行。游标 keyset 分页改用 WHERE id > 上一页最后id 直接定位,跳过这段无用扫描,性能不再随页数恶化。

你应当带走的要点:永远给分页查询加稳定 ORDER BY;offset 的性能坑在深分页才暴露;追求深分页性能就换 keyset 写法。下一步建议把三种 SQL 接到你自己的表里跑一遍,故意翻到第一百页对比响应时间,你会对"跳过前面所有行"的代价有直观感受。

延伸学习

想把这块知识系统补齐,可以按这个顺序来:

  1. 先跟着 MySQL 入门课程 把查询与索引在真实库里练熟;
  2. 想看标准分页语法,回读这篇 SQL 分页查询详解笔记 补充 limit 参数用法;
  3. 关心性能,参考 MySQL 回表优化笔记 理解索引回表对查询速度的影响。

常见问题

Q:LIMIT offset, size 和 LIMIT size OFFSET offset 有区别吗?

语义等价、执行一样。前者是 MySQL 风格、写起来短;后者是标准 SQL 写法、参数顺序更清晰不易读反。团队统一用哪种都行,关键是要一致,别混着写导致把"取几条"和"跳几条"搞反。

Q:为什么深分页会变得很慢?

因为 offset 要先把前面 offset 行全部读出来再丢弃,只留最后一段。翻得越深,被扫描又丢弃的行越多,开销随页码线性增长。加索引只能加速定位,无法消除"跳过前面所有行"这个量级问题。

Q:游标 keyset 分页有什么代价?

它用 WHERE id > 上一页最后id 取代 offset,性能不再随页数恶化,代价是不能直接"跳到第 N 页",只能顺序翻下一页。列表流、无限滚动、消息时间线这类场景最合适;需要任意跳页的后台管理,用 LIMIT offset 更简单。

0 人点赞