


























分库分表后,数据分散在多个物理表中。要做 ORDER BY time LIMIT 10 OFFSET 100,你无法知道第 101-110 条数据在哪个分片上,必须查询所有分片再合并。
假设有 10 个分片:
LIMIT 110(offset + limit)深分页问题:OFFSET 越大,性能越差(数据膨胀严重)。
原理:
每个分片:SELECT * FROM t ORDER BY time LIMIT offset + N
应用层:合并所有结果 → 全局排序 → 取第 offset 到 offset+N 条
示例(offset=100, limit=10, 2个分片):
分片1: 查 110 条 → 返回 110 条
分片2: 查 110 条 → 返回 110 条
应用层: 220 条排序 → 取第 101-110 条
优缺点:
适用场景:数据量小、并发低、不会深分页
原理:不用 offset,用上一页最后一条数据的排序字段值作为下一页的起点。
第一次请求:
-- 前端传:page=1, size=10
SELECT * FROM t ORDER BY id LIMIT 10
返回:last_id = 第10条的id = 100
下一页请求:
-- 前端传:cursor=100, size=10
SELECT * FROM t WHERE id > 100 ORDER BY id LIMIT 10
分库分表改造:
-- 每个分片执行
SELECT * FROM t WHERE id > 100 ORDER BY id LIMIT 10
-- 应用层合并所有分片结果(最多 10 × 分片数条)→ 取最小的 10 条
优缺点:
适用场景:移动端列表、网页滚动加载、时间线
原理:分库分表只做单点查询(按 ID 精确查),复杂排序/聚合/搜索走搜索引擎。
架构:
复杂查询请求 → ES/ClickHouse(同步数据)→ 返回 ID 列表
再根据 ID 列表 → 分库分表中批量取详情
数据同步方案:
优缺点:
适用场景:后台管理、运营系统、数据报表
原理:利用相对位置,减少数据膨胀。以 ORDER BY id LIMIT 10 OFFSET 100 为例:
步骤1:每个分片查 LIMIT 100+10,记录每个分片的最小 id
分片1: 查110条,最小id=100
分片2: 查110条,最小id=200
分片3: 查110条,最小id=150
步骤2:全局排序这 3 个最小值,取第 100 条落在哪个分片
排序: [100(分片1), 150(分片3), 200(分片2)]
第100条在分片1范围内 → 目标在分片1
步骤3:精确计算 offset,只查目标分片
分片1:目标 id 范围 = 100 + (100 - 前一个分片的总数)
...
优缺点:
结论:理论方案,工业界基本放弃。
| 方案 | 实现难度 | 性能 | 是否支持跳页 | 生产落地 | 推荐指数 |
|---|---|---|---|---|---|
| 归并取N | 简单 | 差(深分页线性下降) | ✅ | ✅ 小数据量 | ⭐⭐ |
| 游标 | 中等 | 好(稳定) | ❌ | ✅ 广泛应用 | ⭐⭐⭐⭐⭐ |
| ES/CK | 复杂 | 好 | ✅ | ✅ 中大型项目 | ⭐⭐⭐⭐ |
| 二次查询 | 极难 | 较好 | ✅ | ❌ 极少用 | ⭐ |
| 场景 | 推荐方案 |
|---|---|
| C端列表(如订单列表) | 游标分页(不用 offset) |
| B端管理后台 | ES/CK + 游标分页 |
| 导数据/批量任务 | 游标分页 + 流式处理 |
| 数据量小(< 100 万) | 归并取N + 限制最大 offset |
| 现有业务已用 offset | 限制 offset ≤ 1000,超过则拒绝 |
跨分页查询的核心痛点是 offset 越大性能越差,业界主流方案是改用游标分页(滚动加载),复杂查询走 ES/ClickHouse,不再纠结于在分库分表中实现深分页。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。