分页查询是每个开发者必用的功能,但当你要查第100万页时,数据库可能会直接崩溃!
一、先看震撼对比结果 🔥
我们直接测试两种查询的性能差异:
-- 快速查询(0.001秒)
SELECT * FROM user ORDER BY id LIMIT 10;
-- 慢速查询(12.8秒!)
SELECT * FROM user ORDER BY id LIMIT 1000000, 10;
执行时间对比表:
查询类型 | 偏移量 | 执行时间 | 扫描行数 |
---|---|---|---|
LIMIT 10 | 0 | 0.001秒 | 10 |
LIMIT 1000000,10 | 1000000 | 12.8秒 | 1000010 |
二、为什么偏移量越大越慢?🤔
1. 简单分页原理(LIMIT 10)
MySQL只需:
- 定位到符合条件的第一条数据
- 连续读取10行
- 返回结果
2. 大偏移分页原理(LIMIT 1000000,10)
MySQL必须:
- 定位到符合条件的第一条数据
- 顺序扫描100万+10行
- 丢弃前100万行
- 返回最后10行
三、核心问题解析 ⚡️
1. 罪魁祸首:全表扫描
- MySQL不知道第100万行在哪
- 必须从头开始数到100万行
- 相当于让你从字典第1页翻到第1000页
2. 关键公式
总耗时 = 定位时间 + (偏移量 × 单行扫描时间) + (所需行数 × 单行扫描时间)
当偏移量达到百万级,前100万行的扫描时间成为主要开销!
四、优化方案:这样写才高效 🚀
1. 子查询优化法(推荐)
SELECT * FROM user
WHERE id >= (SELECT id FROM user ORDER BY id LIMIT 1000000, 1)
ORDER BY id LIMIT 10;
原理:先用索引快速定位起始位置,再取数据
2. 连续分页优化
-- 记住上次查询的最大ID
SELECT * FROM user
WHERE id > 上一页最大ID
ORDER BY id LIMIT 10;
3. 性能对比验证
方案 | 100万偏移耗时 | 扫描行数 |
---|---|---|
原始LIMIT | 12.8秒 | 1000010 |
子查询优化 | 0.15秒 | 10 |
连续分页 | 0.001秒 | 10 |
五、什么时候可以不优化?😌
当出现以下情况时,原始LIMIT
仍然高效:
- 偏移量很小(比如前100页)
- 表数据量少(小于1万行)
- 覆盖索引生效(查询字段全在索引中)
六、总结:避坑指南 ✅
- ⚠️ 大偏移量分页是性能杀手
- ✅ 超过1000页的分页必须优化
- 💡 优先使用连续分页(记录上一页ID)
- 🔧 大数据量用子查询+索引优化
记住:数据库不会自动跳过前100万行,它真的会一行行数过去! 优化后性能可提升100倍以上,赶紧检查你的分页代码吧!
思考题:你的项目中分页最大偏移量是多少?遇到过性能问题吗?欢迎评论区讨论!💬