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

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

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


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


总结

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

  • 常见三类方案:

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

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

一句话总结:

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

相关推荐
SelectDB3 分钟前
Apache Doris 中的 Data Trait:性能提速 2 倍的秘密武器
数据库·后端·apache
zhengzizhe12 分钟前
LangGraph4j LangChain4j JAVA 多Agent编排详解
java·后端
程序员鱼皮17 分钟前
又被 Cursor 烧了 1 万块,我麻了。。。
前端·后端·ai·程序员·大模型·编程
福大大架构师每日一题26 分钟前
2025-11-27:为视频标题生成标签。用go语言,给定一个字符串 caption(视频标题),按下面顺序处理并输出一个标签: 1. 将标题中的各个词合并成一
后端
程序员爱钓鱼27 分钟前
Go语言 OCR 常用识别库与实战指南
后端·go·trae
孟祥_成都30 分钟前
nextjs 16 基础完全指南!(一) - 初步安装
前端·next.js
程序员爱钓鱼31 分钟前
使用简单 JSON + 自定义 t 函数实现轻量多语言国际化(无需 next-intl)
前端·javascript·trae
tonydf33 分钟前
动态表单之后:如何构建一个PDF 打印引擎?
后端
allbs35 分钟前
spring boot项目excel导出功能封装——4.导入
spring boot·后端·excel
一 乐43 分钟前
助农平台|基于SprinBoot+vue的助农服务系统(源码+数据库+文档)
前端·javascript·数据库·vue.js·ecmascript·springboot