最近在开发一个数据报表功能,需要从一张大表中查询数据,经过二次清洗后写入报表库。清洗过程中需要调用第三方服务,因此无法使用传统的游标查询方案——因为游标查询通常需要在事务中执行,而事务中调用外部服务可能导致事务超时,进而引发数据库异常。

基于以上限制,我们转向分页查询方案,即分批查询数据、分批清洗写入。下面将介绍几种常用的 MySQL 分页方案,并对其适用场景、优缺点进行分析。

一、LIMIT OFFSET 分页方案

这是最常见的前端分页实现方式,语法简单、易于理解。

基本语法

SELECT * FROM table_name LIMIT 20 OFFSET 1000;
-- 或等价写法:
SELECT * FROM table_name LIMIT 1000, 20;

优点

  • 实现简单,符合直觉。

  • 支持随机跳页,适用于用户交互式分页。

缺点

  • 随着 OFFSET 增大,数据库需要扫描并跳过前 OFFSET 条记录,导致性能下降。

  • 在大数据量(例如超过 50 万行)或深度分页时,查询效率显著降低。

适用场景

  • 数据量在 10 万级以内,或对性能不敏感的场景。

  • 需要支持任意页码跳转的业务,如管理后台表格分页。

二、游标分页(基于ID或时间戳)

也称为“连续翻页”或“键集分页”,通过记录上一页的最后一条记录的ID(或时间戳)来实现下一页查询。

基本语法

SELECT * FROM table_name 
WHERE id > 上次查询的最大id 
ORDER BY id 
LIMIT 20;

优点

  • 避免了 OFFSET 的大量扫描,性能稳定。

  • 适合顺序遍历大数据集,如数据同步、导出任务。

缺点

  • 不支持随机跳转到指定页码。

  • 必须有序且连续,如果ID跳跃大或存在空洞,仍可能扫描较多无效行。

  • 在多条件筛选时,需确保排序字段能有效利用索引。

适用场景

  • 数据导出、流式处理、消息队列消费等顺序读取场景。

  • 不需要跳页,只需“上一页/下一页”的交互。

三、业务记录点位分页(联合索引分页)

可以看作是 LIMIT OFFSET游标分页 的结合体,适用于多条件查询且数据量大的场景。

适用场景举例

假设要查询某一天范围内(如 2025-01-01 至 2025-02-01)的数据,数量在百万级别:

  • 若使用 LIMIT OFFSET,深分页时会扫描大量无效行。

  • 若仅使用 WHERE id > ?,由于数据可能非常老旧,ID 分布松散,仍会扫描很多行。

此时可建立联合索引 (update_time, id),分页查询时同时使用时间范围和ID游标:

基本语法

SELECT * FROM table_name 
WHERE update_time >= '2025-01-01' 
  AND update_time < '2025-02-01' 
  AND id > 上一页最大id 
ORDER BY update_time, id 
LIMIT 20;

优点

  • 结合条件过滤与游标,大幅减少扫描行数。

  • 支持基于业务字段(如时间范围)的高效分页。

缺点

  • 需要设计合适的联合索引。

  • 业务逻辑稍复杂,需维护游标状态。

适用场景

  • 按时间范围、状态等多条件分页查询。

  • 大数据量报表生成、分批处理任务。

四、总结与建议

方案优点缺点适用场景
LIMIT OFFSET简单、支持跳页深度分页性能差小数据量或交互式分页
游标分页性能好、适合顺序读取不支持跳页、需有序连续数据同步、顺序导出
业务记录点位分页性能优、支持多条件索引设计复杂、逻辑稍繁琐大数据量多条件分页

建议

  1. 小数据量或后台管理系统可优先使用 LIMIT OFFSET,简单快捷。

  2. 数据导出或流式处理推荐使用游标分页,性能稳定。

  3. 大数据量且带条件查询应考虑业务记录点位分页,并合理设计联合索引。

  4. 在任何分页场景中,都应尽量避免 SELECT *,只查询需要的字段,并结合索引优化查询性能。