理解大数据量分页查询的性能瓶颈与最佳实践
即使有索引,MySQL 也需要从头扫描到第 100010 条记录,才能确定要返回哪 10 条。
如果 SELECT 的字段不在索引中,需要先定位索引,再回表查完整数据,消耗翻倍。
MySQL 需要将前 100010 条数据加载到内存中排序/过滤,占用大量 buffer pool。
页码越大,m 值越大,查询时间呈线性增长。越往后翻越慢。
| 查询方式 | 第 1 页 (0,10) | 第 100 页 (990,10) | 第 10000 页 (99990,10) | 稳定性 |
|---|---|---|---|---|
| LIMIT m,n | ~5ms | ~50ms | ~5000ms+ | 差 |
| WHERE id > last_id | ~5ms | ~5ms | ~5ms | 优秀 |
利用上一页的最后一条记录的 ID,作为下一页查询的起点。
将 OFFSET 转换为范围查询,减少扫描行数。
先用覆盖索引定位 ID,再回表查完整数据,减少回表次数。
对于超大数据量,限制最大翻页深度,或使用瀑布流无限滚动。
记录上一页的最后一条 ID,下一页用 WHERE id > last_id,性能恒定。
分页字段和排序字段应在索引中,避免全表扫描和大量回表。
对于超大数据量,限制用户能翻到的最大页码,或改用"搜索/筛选"功能。
将 SELECT 字段加入索引,避免回表查询,直接从索引返回数据。