在进销存、电商和物流等具有千万级流水数据的系统中,管理员查询“第 10,000 页历史订单”是常见场景。传统 LIMIT 100000, 20 会导致数据库先扫描十万条记录并逐行回表,产生严重的磁盘随机 IO 阻塞。纳海川数据库优化团队针对此类深分页性能瓶颈给出了系统级解法。
一、问题根因:为什么 LIMIT 越大越慢?
常规语句中,即使查询只取 20 条,MySQL 的存储引擎 InnoDB 仍需从辅助索引找到主键后,执行 100,020 次聚簇索引回表读取整行数据,随后丢弃前 100,000 条,造成大量无谓的 IO 消耗。
二、核心破局方案:延迟关联(Deferred Join)
通过子查询在辅助索引上走覆盖索引,仅获取所需 20 条记录的主键 ID,然后再通过主键 INNER JOIN 获取完整列信息:
-- 优化前耗时 3.8s
SELECT * FROM fa_orders WHERE tenant_id = 1001 ORDER BY id DESC LIMIT 500000, 20;
-- 延迟关联优化后耗时仅 12ms
SELECT t1.* FROM fa_orders t1
INNER JOIN (
SELECT id FROM fa_orders WHERE tenant_id = 1001 ORDER BY id DESC LIMIT 500000, 20
) t2 ON t1.id = t2.id;
三、游标分页(Cursor-based Pagination)终极方案
对于前台移动端长列表无限滚动加载,纳海川禁止使用物理页码,全面推行 WHERE id < :last_seen_id ORDER BY id DESC LIMIT 20 的游标方案,直接借助 B+ 树索引精确定位,查询耗时始终稳定在 2ms 以内。
架构建议:对于超过 1,000 万行的冷数据,应结合 Elasticsearch 进行多维聚合检索,数据库专注高频事务落库,实现各司其职。