大家好,我是小米,31 岁,依旧活跃在互联网一线岗位,继续跟大家分享技术干货。今天我们聊一个经常出现在 MySQL 8.x 面试题 里的问题: "超大分页怎么处理?"
说到分页,可能很多小伙伴第一反应就是 ------ limit offset, size,写起来简单,查小表快得飞起。但一旦数据量上亿,尤其是要查 limit 1000000, 10 这种页码巨大的场景,SQL 立马变成性能杀手。
我先讲个我朋友面试的真实故事。
故事开头:面试里的"灵魂拷问"
前段时间,我朋友阿辉去面一家头部互联网公司,面试官很和气,但抛出的题却直击灵魂:
"假设你们有一张订单表,几千万数据,用户要看第 100 万页,SQL 怎么写?怎么优化?"
阿辉当场懵了,心里想:"分页就分页嘛,加个 limit 不就行?"可话到嘴边又停住,因为他想起自己写过的 limit 1000000, 10 在测试环境跑了半天没结果。
于是,他硬着头皮说:"可以加索引吧......"
面试官笑了笑:"能不能具体点?"
你看,这种题就是面试官的常规武器。能不能答好,直接决定了你是不是只会写 CRUD,还是能做真正的性能优化。
为什么超大分页慢?
我们先回到原理。MySQL 的分页是 "扫描+丢弃" 的过程。比如:
MySQL 会先扫描 1000010 条数据,丢掉前 100 万,再返回 10 条。
换句话说,页码越靠后,浪费的扫描越多,性能呈指数级下降。
这就好比你去排队取快递,快递员一件件往后翻,找到第 100 万个时,你早就下班了。
所以,问题的关键是:如何避免无意义的扫描?
接下来我带大家过一遍面试官想要的几个思路。我会结合场景讲,保证你记得住。
利用索引 + 覆盖条件
最经典的优化就是:不要用 offset,而是利用 索引定位起点。
比如订单表有主键 id,我们可以改成:
这样 MySQL 直接跳过前面数据,定位到 id 较大的部分,不需要做大量丢弃。
这就像快递员直接从第 100 万个快递开始翻,而不是从第一个开始数。
不过注意,这个方案要求分页是 基于主键顺序的。如果你要按创建时间排序,那就得在 created_at 上建索引。
延迟关联(或称"子查询 + join")
还有一个套路:先用索引字段做子查询,获取主键,再回表查询其他字段。
这样子查询部分只走索引,返回很快;主查询只查 10 条数据,避免了大范围扫描。
这就好比你先记下第 100 万个快递的编号,再直接去货架拿,不需要傻傻从头找。
覆盖索引 + 边走边翻页
如果分页需要支持"上一页、下一页",我们可以用 基于游标的分页(cursor based pagination) 。举个例子:
这里的 '2023-05-01 10:00:00' 相当于上一页最后一条数据的时间戳。下一次分页就从这里继续查,效率高得多。
这就是很多大厂 API 的默认分页方式:基于游标,不基于 offset。
业务层面的优化
面试官常常还会追问一句:
"除了 SQL 优化,业务上能怎么搞?"
这就是考察你能不能 跳出数据库思维。
几种思路:
- 限制最大页数:谁会真的翻到第 100 万页?很多系统干脆只允许翻到 100 页。
- 搜索+过滤结合:用户如果要找历史订单,可以先选条件缩小范围,再分页。
- 异步加载 / 下拉刷新:前端做"无限滚动",用户体验好,SQL 压力也小。
这类回答很加分,因为它体现了 技术与业务结合的思维。
MySQL 8.x 的新武器
既然是 MySQL 8.x 面试题,别忘了加点 版本特色,面试官会觉得你真用过。
- 窗口函数:MySQL 8.x 支持窗口函数,我们可以用 row_number() 给结果集编号,然后取某一段:
虽然性能未必比传统分页快,但写法灵活,而且考察你对新特性的掌握。
- CTE(公用表表达式) :在 MySQL 8.x 里可以用 CTE 重写分页逻辑,更清晰,也便于调试。
- InnoDB 隐式主键优化:MySQL 8.x 对主键分页性能优化得更好,面试时可以顺带提一句"升级版本能提升性能"。
总结:怎么在面试中答?
到这儿,我们已经盘点了超大分页的优化思路。那面试的时候,怎么说才显得层次分明?
我给你一个参考答法:
- 先指出问题本质:MySQL 分页是"扫描+丢弃",大页 offset 性能差。
- 再讲 SQL 优化:
-
- 用索引替代 offset
-
- 子查询+join(延迟关联)
-
- 游标式分页(基于主键/时间)
- 补充业务优化:限制页数、增加条件、下拉刷新。
- 顺带提 MySQL 8.x 特性:窗口函数、CTE 等。
这样回答下来,既有深度,又有广度,面试官一定会点头。
番外:真实工作里的选择
最后我想说,很多时候"超大分页"更多是理论题。真实场景下,用户根本翻不到第 100 万页。
所以在实际工作里,我更常用的是 游标分页 + 前端下拉加载,配合 Redis 做热点数据缓存,既能保证体验,又能节省数据库压力。
面试题的意义,不只是考你写 SQL 的能力,而是考你能不能 从底层原理、技术方案、到业务优化,完整地分析问题。
END
好了,今天这篇文章就分享到这里。
如果你正准备面试 MySQL 相关岗位,记住:碰到"超大分页"问题,不要慌。把原理、方案、业务结合一说,面试官一定会觉得你是"能落地的工程师",而不是"只会背八股的候选人"。
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号"软件求生",获取更多技术干货!