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

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

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


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(结果): 既能满足业务需求,也能保证性能稳定性。


总结

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

  • 常见三类方案:

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

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

一句话总结:

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

相关推荐
码事漫谈12 小时前
C++环形缓冲区实践与注意事项
后端
码事漫谈12 小时前
不止于Linux:百花齐放的开源世界与社区的力量
后端
绝无仅有12 小时前
某游戏大厂的常用面试问题解析:Netty 与 NIO
后端·面试·架构
浅影歌年12 小时前
vue3模块中引用公共css变量文件
前端
donotshow12 小时前
DBeaver连接本地MySQL、创建数据库表的基础操作
java·后端
绝无仅有12 小时前
某游戏大厂的 Redis 面试必问题解析
后端·算法·面试
Moonbit12 小时前
月报 Vol.05:alias系统更新,新增 ReadOnlyArray 与 external iterator
后端·编程语言·编译器
王元_SmallA13 小时前
Go环境搭建(vscode调试)
java·后端
盼哥PyAI实验室13 小时前
从搭建到打磨:我的纯前端个人博客开发复盘
前端·javascript
前端初见13 小时前
2025前端面试题大合集
前端