分库分表下的分页查询,到底怎么搞?

今天聊一个分库分表后的经典难题:分页查询 。

很多伙伴在面试或者工作里都被问过这个问题,如果没理清楚,容易一头雾水。那我们就用最简单的大白话,把它捋清楚说明白。


1. 不是所有场景都需要分页方案

分页问题只有在 跨库或跨表查询 时才会变复杂。

举个例子:

  • 如果查询条件里总是带 分片键(比如查某个用户ID的数据,或者查某个时间片的数据),那它就是查某一个分片的数据。
  • 这种情况和查单表一模一样,不存在什么分页难题。

👉 所以第一步一定要问:这次查询到底是不是跨分片的?


2. 三种主流解决方案

当我们真的遇到跨分片分页时,常见的有三种办法:

方案 核心思想 优点 缺点
方案1:专用中间件/数据库 (如 Elasticsearch、TiDB) 把分库分表的数据同步到更适合做复杂查询的系统里,由它来处理分页。 性能高,工业界常用方案。 要保证数据同步一致性(MySQL → ES)。
方案2:开源框架 (如 ShardingSphere) 应用还是写"单表SQL",框架在背后把SQL拆开,去各个分片拉数据,再在内存里排序、分页。 对应用几乎零改动,开发体验好。 深度翻页性能差。
方案3:业务妥协 跟产品经理沟通,限制查询范围,不搞跨分片分页。例如只查当前分片,或者提示用户"仅显示部分结果"。 最简单,直接回避问题。 对业务体验可能有影响。

3. 全局查找法的真相

面试中最喜欢问的就是方案2里提到的 全局查找法。

⚙️ 原理图

flowchart TD A[客户端 SQL LIMIT offset,size] --> B[各分片执行 LIMIT 0, offset+size] B --> C[汇总数据] C --> D[内存归并排序] D --> E[取 offset 之后的 size 条数据]

⚠️ 问题

  • 正确性没问题,但如果查询第 100,000 页:

    • 每个分片要查几十万甚至上百万条数据。
    • 内存里还要排序和裁切。
    • 极容易 OOM(内存溢出),速度慢到怀疑人生。

所以: 👉 全局查找法能用,但翻页浅一点还行,深度翻页会死。


4. 优化:禁止跳页,顺序翻页更香

解决深度翻页问题的最佳实践是:基于上一页最大 ID 翻页。

✅ 做法

  • 第 1 页:

    sql 复制代码
    SELECT * FROM table ORDER BY id LIMIT size;
  • 第 2 页:

    sql 复制代码
    SELECT * FROM table WHERE id > {上一页最大id} ORDER BY id LIMIT size;

👍 优点

  • 每次只查一页,性能极好。
  • 和 offset 大小无关,不怕深度翻页。

👎 缺点

  • 不能直接跳到第 100 页。
  • 只能一页一页往下翻,像刷微博/抖音一样。

👉 但对大多数场景(信息流、消息列表),完全够用。


5. 不推荐的方案:二次查询法

有些文章会提到"二次查询法"。 它实现复杂,还可能遇到数据分布不均的问题,结果不可靠。

一句话:不推荐使用。


6. 面试怎么答(STAR 法则)

如果在面试被问到,可以按 STAR 模型来回答:

  • S(情境): 系统做了分库分表后,跨分片分页成了难题。

  • T(任务): 需要一个能保证全局分页正确性的方案。

  • A(行动):

    1. 首先评估业务,能不能限制查询范围,直接规避问题。
    2. 如果必须实现,首推用 Elasticsearch/TiDB 这类系统。
    3. 如果必须在数据库层面搞,就用 ShardingSphere 的全局查找法,但要说明深度翻页问题。
    4. 针对深度翻页,再提出"基于上一页最大ID"的优化。
  • R(结果): 既能满足业务需求,也能保证性能稳定性。


总结

  • 不是所有分库分表都有分页问题,只有跨分片才需要考虑。

  • 常见三类方案:

    • 中间件/数据库(推荐)
    • 开源框架(方便但有性能坑)
    • 业务妥协(直接回避)
  • 全局查找法能用,但深度翻页会炸。

  • 最佳实践:禁止跳页 + 顺序翻页。

一句话总结:

能规避就规避,能交给专用系统就交给专用系统,实在要做就用连续翻页。

相关推荐
xcs194056 小时前
前端 vue 的前端页面debugger 进不去
前端·javascript·vue.js
代码什么用7 小时前
Spring基础使用
java·后端·spring
明月_清风7 小时前
Deno 终局来了:从挑战 Node 到被 Cloudflare 收编
前端·后端·node.js
蜗牛互联网8 小时前
Java 17 HttpClient调用文件转写API的超时与失败回退
java·人工智能·后端
Csvn8 小时前
框架性能优化
前端
回眸&啤酒鸭10 小时前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户693717500138410 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员10 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端
惜鸟10 小时前
从源码看 pi 的上下文管理:原始数据永久保留,模型视角按需裁剪
后端
小兔子10 小时前
Python 的 GIL 与 free-threading:3.13 之后「去 GIL」走到哪一步了
前端