在企业级项目中,深分页查询经常会成为性能瓶颈。本篇文章总结了我在实践中优化深分页 sql 的经验,包括 执行计划分析、索引优化、游标分页改写 等内容。
一、问题场景
假设我们有一张订单表 orders,包含字段:
id, user_id, status, total_amount, create_time
原始查询为:
select id, user_id, status, total_amount, create_time from orders where user_id = 12345 order by create_time desc limit 990, 10;
- 业务背景:查询某用户最近的订单,且需要支持分页。
- 数据量假设:企业级通常几十万到几百万条订单。
二、原始 sql 执行计划分析
使用 explain查看原始 sql:
| id | select_type | table | type | possible_keys | key | key_len | rows | extra |
|---|---|---|---|---|---|---|---|---|
| 1 | simple | orders | ref | user_id | user_id | 4 | 50 | using filesort |
分析:
- type=ref → 使用了
user_id索引进行精确匹配。 - key=user_id → 索引选择正确。
- extra=using filesort → order by create_time desc 未覆盖索引,需要额外排序。
- 扫描行数 → mysql 会扫描前 990 条行再丢弃(limit 偏移量大),深分页效率低。
✅ 结论:单列索引只能加速 where 条件,排序仍需额外操作。
三、复合索引优化
为了提升查询效率,我们创建复合索引:
alter table orders add index idx_user_create (user_id, create_time desc);
- 作用:
- 覆盖
where user_id=…条件。 - 覆盖
order by create_time desc条件。
- 覆盖
- 优化后 explain:
| id | select_type | table | type | possible_keys | key | key_len | rows | extra |
|---|---|---|---|---|---|---|---|---|
| 1 | simple | orders | ref | idx_user_create | idx_user_create | 8 | 20 | using index condition |
分析:
- type=ref → ref → 使用索引范围扫描,避免全表扫描。
- key_len=8 → 复合索引长度增加。
- extra=using index condition → icp (index condition pushdown) 优化回表行数。
✅ 结论:复合索引同时覆盖 where + order by,大幅减少扫描行数和排序成本。
四、游标分页改写
深分页仍有偏移量大的问题,可以改写为游标分页:
select id, user_id, status, total_amount, create_time from orders where user_id = 12345 and create_time < '2024-06-01 12:00:00' order by create_time desc limit 10;
- 优势:
- 不用 offset,避免扫描前面大量行。
- 对大数据量分页性能稳定。
- explain 输出:
| id | select_type | table | type | possible_keys | key | key_len | rows | extra |
|---|---|---|---|---|---|---|---|---|
| 1 | simple | orders | range | idx_user_create | idx_user_create | 8 | 10 | using index condition |
✅ 结论:扫描行数恒定,排序在索引中完成,性能最佳。
五、实践总结
- 深分页性能问题:
- offset 大时,mysql 会扫描并丢弃大量行。
- order by 未覆盖索引 →
filesort。
- 优化策略:
- 复合索引覆盖 where + order by。
- 游标分页替代大 offset 分页。
- explain 解析技巧:
- type → 尽量是
ref、range或const,避免all。 - key / key_len → 关注索引是否被正确使用。
- extra → 理解
using index condition和using filesort。 - 经验总结:
- 使用 icp 能减少回表行数。
- 游标分页适合大数据量分页查询。
- sql 优化不仅是索引,改写查询逻辑同样重要。
到此这篇关于mysql 深分页查询优化实践与经验分享的文章就介绍到这了,更多相关mysql深分页查询内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论