您的当前位置:首页 >IT科技 >三个巧技,让分库分表 LIMIT 翻页性能直接拉满! 正文
时间:2025-11-04 21:03:37 来源:网络整理编辑:IT科技
线上出了个离谱问题:运营同学在后台导出近 3 个月订单时,点击分页到第 100 页,直接把数据库查崩了。排查后发现,代码里写了LIMIT 9900, 100,在分库分表场景下,这行 SQL 相当于让
线上出了个离谱问题:运营同学在后台导出近 3 个月订单时,三个巧技点击分页到第 100 页,让分直接把数据库查崩了。库分排查后发现,翻页代码里写了 LIMIT 9900,直接 100,在分库分表场景下,拉满这行 SQL 相当于让 8 个分片各查 1 万条数据,三个巧技再拉到应用层内存排序,让分直接把内存溢出了。库分
其实分库分表的翻页分页查询,藏着很多反常识的直接奇技淫巧,但这些技巧都有严格的拉满适用边界,用错了反而会埋坑。三个巧技我来分享 3 个实战中验证过的让分骚操作。

单表分页用 LIMIT offset, size 没问题,但分库分表后,数据散在多个分片里,比如你要查 LIMIT 10000, 10(第 1001 页),会发生两件离谱的事:
全分片扫描:每个分片都要执行 LIMIT 0, 10010(因为不知道其他分片的数据分布,只能把前 10010 条都查出来,避免漏数据);
内存爆炸排序:假设 8 个分片,每个返回 10010 条,共 8 万多条数据,全拉到应用层排序,再截取第 10000-10010 条。内存和 CPU 直接飙红,我之前见过最夸张的b2b信息网案例,offset=100000 时,一个分页请求耗时 12 秒,直接触发服务熔断。
所以我们下边要讲的都是绕开全分片扫描 + 内存排序,但每个方案的适用场景天差地别,核心原则:不盲目追高性能,先看业务场景是否匹配。
锚点分页,性能最优,但仅限加载更多场景。
这是我最常用的技巧,核心思路是用数据本身的有序字段当锚点,替代 offset,比如按自增 ID 或时间戳分页。但注意:不是所有有序字段都能用,必须满足分片内 + 分片间都有序。
假设订单表按 ID 范围分 3 个分片:
分片 1:ID 1-10000(分片内有序,且小于分片 2 的 ID);分片 2:ID 10001-20000(同理);分片 3:ID 20001-30000(同理);要查第 2 页(10 条 / 页),步骤如下:
查第 1 页时:执行 ORDER BY id DESC LIMIT 10,拿到最后一条数据的 ID 是 last_id=100(这个 ID 就是服务器托管锚点);查第 2 页时:直接用 WHERE id < 100 ORDER BY id DESC LIMIT 10;查第 3 页时:再用第 2 页最后一条的 ID(比如 90)当锚点,执行 WHERE id < 90 ORDER BY id DESC LIMIT 10。每个分片都能独立执行 WHERE id < xxx LIMIT 10,只返回 10 条数据(不用查前 N 条)。比如查第 1001 页,每个分片也只返回 10 条,汇总后排序取 10 条,网络和内存开销直接降为原来的 1/1000。
刚才的云服务器锚点分页不支持跳页,但有些场景比如后台管理系统,又必须要跳页,怎么办?我之前在电商后台做订单导出时,用过分片标记法,核心是给每个库、表记录数据范围和总量,快速定位目标页在哪个分片。
分片标记法支持跳页,但必须控制元数据一致性。
假设订单表按用户 ID 范围分 2 库,每库按时间分 12 表(如库 1 - 表 202401、库 1 - 表 202402...),先在 Redis 里维护 库、表级别的元数据:
库 - 表
起始 ID
结束 ID
数据总量
库 1 - 表 202401
1
5000
5000
库 1 - 表 202402
5001
12000
7000
库 2 - 表 202401
12001
18000
6000
....
....
..18000
6000
现在要查 LIMIT 15000, 10(第 1501 页),步骤如下:
查元数据定位库、表:计算累计数据量,库 1 - 表 202401(5000)+ 库 1 - 表 202402(7000)= 12000 <15000,再加上库 2 - 表 202401 的 6000,累计 18000>15000,所以目标在库 2 - 表 202401;计算表内偏移量:表内偏移量 = 15000 - 12000 = 3000,所以库 2 - 表 202401 执行 LIMIT 3000, 10;直接返回结果:因为库、表按 ID 有序,查询结果就是全局第 15000-15010 条,不用汇总其他分片。1.元数据必须实时但不能强同步:
数据新增、删除时,要同步更新 Redis 元数据,但高并发下不能加分布式锁(会卡住业务),建议用定时 + 增量日志:每 5 分钟全量统计一次,同时记录增量(如新增 100 条、删除 10 条),查询时叠加增量;
若允许最终一致性(如后台查询允许误差 10 条),这个方案很稳;若要强一致,只能放弃跳页,用锚点分页;
2.不支持非分片键排序:如果要按支付时间排序(分片键是用户 ID),支付时间在 “库 - 表” 内无序,元数据无法定位,仍需全分片扫描。
反向分页,仅适用于查最后 1 页,别乱用
这个技巧最反常识,但局限性也最大。如果要查最后几页数据(比如用户查最早的订单),用普通分页会查 LIMIT 9990, 10,但可以反向查,避开大 offset。
假设订单表按 ID 范围分片,总数据量 10000 条(1000 页,10 条 / 页),要查最后 1 页(ID 9991-10000):
反向查锚点:执行 ORDER BY id ASC LIMIT 10,拿到最前面 10 条的 ID(1-10),取最大 ID 作为反向锚点(10);查最后 1 页:执行 WHERE id > 10 ORDER BY id DESC LIMIT 10,拿到的就是 ID 10000-9991(最后 10 条);调整顺序:如果需要正序展示,把结果再倒过来即可。因为 LIMIT 0, 10 比 LIMIT 9990, 10 快 100 倍. 每个分片查前 10 条数据,汇总后取最大的 10 个 ID 作为锚点,再查大于锚点的数据,避免了大 offset 扫描。
其实分库分表分页的核心不是炫技,而是在业务和技术之间找平衡。能通过产品设计规避跳页(用加载更多),就优先用锚点分页(性能最优),必须跳页就用分片标记法(接受最终一致性);实在没办法才考虑中间件(如 ShardingSphere 的全局排序)。
电脑远程连接显示错误的解决方法(教你如何应对常见的远程连接显示错误)2025-11-04 19:57
有价值的域名都是来自哪的?新手找域名这里不可忽视2025-11-04 19:49
对域名估价怎么看?新手有什么方法进行域名价值参考?2025-11-04 19:34
新手如何注册海外域名?海外域名有什么价值?2025-11-04 19:28
USP无线网卡安装教程(详细指南帮助您轻松安装和使用USP无线网卡)2025-11-04 19:24
注册国外域名有什么不同方式?新手要注意哪几点?2025-11-04 19:12
域名主机如何合理选择呢?新手要注意哪些常见问题?2025-11-04 19:03
小白选老域名需要注意什么问题?有什么细节?2025-11-04 18:51
华为台灯电脑支架安装教程(一步步教您如何安装华为台灯电脑支架)2025-11-04 18:38
怎么做好域名投资?新手必须要注意这些2025-11-04 18:23
手工制作电脑支架蛋糕教程(用简单材料打造独特创意,将甜点与科技相结合)2025-11-04 21:03
中文域名比英文域名的优势吗?两者有什么区别?2025-11-04 20:49
选域名有些容易忽略的地方?小白选域名要知道什么?2025-11-04 20:34
新手怎么才能挑选有投资价值的域名?有什么好的技巧?2025-11-04 20:28
U盘制作系统教程18(一步步教你如何使用U盘制作自己的便携式系统)2025-11-04 20:28
怎样的域名别人容易搜寻?选域名的技巧要学会哪些?2025-11-04 20:18
新手知道的选择域名技巧有哪些?该怎么做?2025-11-04 19:37
面对域名投资需要知晓什么?域名投资有什么看法?2025-11-04 19:10
以k快启动安装教程(轻松安装k快启动,提升系统启动速度)2025-11-04 19:06
date域名可以做网站吗?date的网站后缀未来会如何?2025-11-04 18:41