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 不愁。

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

相关推荐
通往曙光的路上1 小时前
mysql3
数据库
阿坤带你走近大数据1 小时前
什么是 REDO LOG,它在 Oracle 数据库中的作用是什么?
数据库·oracle
东风破1371 小时前
DM8搭建同构(dm-dm)及异构数据库(dm-oracle,dm-mysql)的dblink
数据库·mysql·oracle
凭X而动2 小时前
postgresql18.1部署
数据库·postgresql
万邦科技Lafite2 小时前
京东商品详情 API 接口全面讲解
java·数据库·redis·api·电商开放平台
无风听海2 小时前
MongoDB GridFS 一些处理细节解析
数据库·mongodb
青云计划2 小时前
Mysql
数据库·mysql
BestHeaker2 小时前
CC Switch 全能使用教程
后端·职场和发展·跳槽·学习方法
海棠Flower未眠2 小时前
Spring Boot 3 + JPA多模块系统对MySQL和DORIS进行多数据源集成实战(荣耀典藏版)
spring boot·后端·mysql