MySQL深分页优化:从LIMIT 1000000,10到毫秒级响应的三种写法

我是小耶,干运营半路出家的野生DBA------写功课只是为了我踩过的坑,你们别再踩了!

刚转行时我写的分页查询是 SELECT * FROM orders ORDER BY id LIMIT 1000000, 10。前100页还好,用户翻到第200页就开始转圈。后来才知道这是典型的"深分页"问题。

先解释一个基础概念:LIMIT M, N ​到底怎么执行?

数据库拿到这个命令后,会老老实实从第一行开始扫描,扫到第 M+N 行,然后扔掉前面的 M 行,只返回最后 N 行。就像你翻一本1000页的书,要读第900页到910页,但你不能直接翻到900页,只能从第一页开始一页一页翻。M越大,翻的页数越多,越慢。

为什么很多人会踩这个坑?

因为小数据量时(比如几千行)感觉不到慢,一旦表增长到百万、千万级,LIMIT 1000000, 10 可能需要扫描上百万行,耗时几秒甚至几十秒。

优化方法一:记住上次位置(游标法)

适用于"下一页"按钮,不需要跳页。假设上一页最后一条记录的 id 是 1000000:

复制代码
SELECT * FROM orders WHERE id > 1000000 ORDER BY id LIMIT 10;

这就像你合上书,在1000页夹一张书签,下次直接翻到书签位置。数据库利用主键索引快速跳过,只扫描10行,速度恒定在毫秒级。

缺点​:不能跳页(比如直接点第1000页),且如果id之间有删除,每页数量可能不均匀,但通常可接受。

优化方法二:子查询先定位起始id(支持跳页)

如果用户非要跳页,可以用子查询先查出第 M 条开始的 id,再取数据:

复制代码
SELECT * FROM orders 
WHERE id >= (SELECT id FROM orders ORDER BY id LIMIT 1000000, 1) 
ORDER BY id LIMIT 10;

里面的子查询 SELECT id FROM ... LIMIT 1000000,1 只查id列,而id列通常有主键索引,索引体积小,扫描速度快。拿到起始id后,外层 WHERE id>=... 的主键查询也是走索引。

实测​:500万数据,传统写法2.3秒,改后0.05秒。

优化方法三:延迟关联(当你要查所有列时特别有效)

如果必须 SELECT * 返回所有字段,可以先查主键,再关联回原表:

复制代码
SELECT * FROM orders 
JOIN (SELECT id FROM orders ORDER BY id LIMIT 1000000, 10) AS tmp USING(id);

子查询只取id(索引覆盖,极快),然后通过id去原表批量取完整行。比直接 SELECT * 少了很多不必要的数据传输。

什么时候不需要优化?

数据量小(几千行)或用户几乎不走翻页,可以用简单写法。但一旦成为通用查询,建议提前优化。

学会了你将:

  • 避免因深分页导致接口超时、数据库CPU飙升。
  • 不用加额外缓存的成本,纯粹靠SQL改写就能大幅提升体验。
  • 面试或技术分享时,这是一个非常经典的优化案例,能展示你对数据库执行细节的理解。

小耶在手,SQL 不愁。

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽......我们下次见~

相关推荐
亲亲小宝宝鸭10 小时前
前端性能监控:web-vitals
前端·性能优化·监控
Databend11 小时前
在 AWS 中国峰会逛了一天,我在 Databend 展台看到了 Agent 数据基础设施的新思路
数据库·人工智能·agent
NE_STOP1 天前
Vibe Coding -- Claude Code 的核心配置与常用命令
程序人生
李白客2 天前
KES新版MySQL兼容能力再升级意味着什么?
mysql·国产数据库
ClouGence2 天前
Oracle 数据同步为什么会出现数据不一致?长事务是常被忽略的原因
数据库·后端·oracle
飞将2 天前
从零实现数据库(2)——HashIndex + IndexManager
数据库
Nturmoils3 天前
订单列表慢查询,先看 WHERE、ORDER BY 和 LIMIT
数据库
渣波3 天前
拒绝 SQL 焦虑!手把手带你用 NestJS + Prisma + DTO 写出“防弹”级后端代码
javascript·数据库·后端
Jim6003 天前
【吃透 MySQL InnoDB连载】第 1 章・解密线上数据库高频故障
mysql