澳五机器人 游标分页(Seek Method / Keyset Pagination)
结合你此前关注MySQL性能调优、建表规范及高并发场景的相关背景,针对千万级单表的分页查询,核心痛点在于传统 LIMIT offset, size 在深分页(如 offset > 10万)时会导致全表扫描或大量回表,性能急剧下降。以下是三种工业级优化方案:
一、游标分页(Seek Method / Keyset Pagination)
这是性能最优解,适用于连续翻页场景(如无限滚动加载)。
原理:利用上一页最后一条记录的主键或唯一索引值作为下一页的查询起点,避免扫描废弃数据。
SQL示例:
sql
-- 假设按 id 升序排列,上一页最后一条 id 为 100000
SELECT * FROM table_name WHERE id > 100000 ORDER BY id ASC LIMIT 20;
优势:无论翻到第几页,时间复杂度恒定为 O(logN) + O(M),彻底解决深分页性能问题。
局限:不支持随机跳页(如直接跳至第 1000 页)。
二、延迟关联(Deferred Join)
适用于必须支持随机跳页且无法改造业务逻辑的场景。
原理:先通过覆盖索引查出所需的主键 ID,再与原表进行 INNER JOIN 获取完整字段,减少回表次数。
SQL示例:
sql
SELECT t.*
FROM table_name t
INNER JOIN (
SELECT id FROM table_name ORDER BY id ASC LIMIT 100000, 20
) AS tmp ON t.id = tmp.id;
优势:子查询仅扫描索引树,避免了大量随机 IO 回表,性能比传统分页提升显著。
注意:ORDER BY 字段必须有索引,否则子查询依然会慢。
三、搜索引擎兜底(Elasticsearch)
适用于复杂条件筛选、模糊搜索及极高并发读取场景。
原理:将 MySQL 数据同步至 Elasticsearch,利用 ES 的倒排索引和深分页优化机制(如 search_after)处理查询。
优势:完全卸载 MySQL 的检索压力,支持毫秒级响应复杂多维查询。
成本:引入额外中间件,需维护数据一致性(通过 Canal/Binlog 同步)。
四、避坑指南
禁止无索引排序:ORDER BY 字段若无索引,千万级数据排序将触发文件排序(Filesort),导致 CPU 飙升甚至OOM。
限制最大页数:在产品层面限制用户只能查看前 N 页(如前 100 页),超出部分引导使用搜索功能,从源头规避深分页。
统计总数优化:SELECT COUNT(*) 在千万级表中极慢,若非必要,可移除总数统计或使用 Redis 缓存计数值。
需要我为你整理一份基于 MyBatis-Plus 实现游标分页的工具类代码吗?帮你快速落地高性能分页方案。