实战 | OceanBase单表亿级数据,如何把分页查询从“快死了”优化到“毫秒级”?

很多同学在MySQL时期养成了limit offset, size 的习惯,换到OceanBase后依然这么写。结果数据量到了5000万+,翻到第100页直接超时——这是分布式数据库最典型的新手病

今天我带你把三种主流分页优化方案 一次性讲透,包含原理剖析+SQL写法+性能实测数据

方案一:传统limit offset (反面教材)

SQL写法:

sql

SELECT * FROM orders ORDER BY create_time DESC LIMIT 100000, 20;

执行原理:
OB执行器会扫描前100020行,丢弃前100000行,只返回最后20行 。扫描行数随着页码线性增长,翻到1000页时扫描百万行,必慢。

实测: 5000万表,翻到第500页(offset=10000)→ 耗时约8秒
翻到第5000页(offset=100000)→ 耗时45秒+

结论: 严禁在生产环境使用大offset分页

方案二:游标分页(业界标准答案)

核心思想: 不计算“跳过的行数”,而是记住“上一页的最后一条”。

SQL写法:

sql

– 第一页:正常查询 SELECT id, order_no, amount, create_time FROM orders WHERE status = ‘COMPLETED’ ORDER BY id ASC LIMIT 20; – 第二页:传入上一页的最大id SELECT id, order_no, amount, create_time FROM orders WHERE status = ‘COMPLETED’ AND id > 10086 – 上一页最后一条的id ORDER BY id ASC LIMIT 20;

性能特征:

  • 无论翻到多少页,每次扫描行数=20+索引快速定位
  • 索引使用完美,响应稳定在10ms以内

适用场景:

  • 瀑布流加载(App首页、消息列表)
  • 按主键/唯一索引排序

缺点: 不支持指定页码跳转(用户说“我要直接去第100页”就没辙)。

方案三:覆盖索引+延迟关联(解决大宽表+跳页)

适用场景:

  • 必须支持页码跳转
  • 表很宽(几十个字段),不能只查索引
  • 但你不能接受limit 100000,20 的45秒

原理:
先利用覆盖索引快速查出20条记录的主键ID ,再用主键回表取完整数据。覆盖索引层完全不回表,速度极快

SQL写法:

sql

– 步骤1:覆盖索引查出主键(只需扫描索引,不回表) SELECT id FROM orders WHERE status = ‘COMPLETED’ ORDER BY create_time DESC LIMIT 100000, 20; – 步骤2:用这20个id回表取完整字段 SELECT * FROM orders WHERE id IN (上一步查出的20个id) ORDER BY create_time DESC;

实测对比(5000万表,status过滤后200万行):

方案 offset=10000 offset=100000
直接limit 10000,20 8.2秒 45.6秒
覆盖索引+延迟关联 0.09秒 0.11秒

结论: 延迟关联方案将45秒的查询压到了0.1秒 ,性能提升450倍。

方案四:分区裁剪(OceanBase独家优化)

如果order_time 是分区键,并且你的分页条件带时间范围,一定要开启分区裁剪

参数确认:

sql

SHOW VARIABLES LIKE ‘ob_enable_partition_pruning’; – 确保为 ON

原理: OB只扫描命中分区,其他分区根本不碰。

分区设计建议:

sql

CREATE TABLE orders ( id BIGINT NOT NULL, order_time DATETIME NOT NULL, … ) PARTITION BY RANGE (UNIX_TIMESTAMP(order_time)) ( PARTITION p202601 VALUES LESS THAN (UNIX_TIMESTAMP(‘2026-02-01’)), PARTITION p202602 VALUES LESS THAN (UNIX_TIMESTAMP(‘2026-03-01’)), … );

总结:分页场景选型速查表

业务场景 推荐方案 核心要点
App首页下拉加载 游标分页 WHERE id > 上一页最大id
管理后台带页码跳转 覆盖索引+延迟关联 先查ID,再回表
带时间范围的大表翻页 游标分页+分区裁剪 时间分区 + 边界传递
极小表(<10万) 传统limit offset 没必要折腾

留言区互动 :你踩过最深的翻页坑是什么?我用具体SQL帮你分析优化点。

【标签】 #SQL优化 #分页查询 #索引设计 #性能调优

1 个赞

这个问题涉及到id和time的平衡,根据我的经验,适当调整offset会有帮助。

学习了

很好