LIMIT 9900, 100,在分库分表场景下,这行 SQL 相当于让 8 个分片各查 1 万条数据,再拉到应用层内存排序,直接把内存溢出了。
LIMIT offset, size 没问题,但分库分表后,数据散在多个分片里,比如你要查 LIMIT 10000, 10(第 1001 页),会发生两件离谱的事:
LIMIT 0, 10010(因为不知道其他分片的数据分布,只能把前 10010 条都查出来,避免漏数据);
offset=100000 时,一个分页请求耗时 12 秒,直接触发服务熔断。
锚点,替代 offset,比如按自增 ID 或时间戳分页。但注意:不是所有有序字段都能用,必须满足分片内 + 分片间都有序。
-
分片 1:ID 1-10000(分片内有序,且小于分片 2 的 ID);
-
分片 2:ID 10001-20000(同理);
-
分片 3:ID 20001-30000(同理);
-
查第 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 mod 3哈希分片,分片 1 的 ID 可能是 3、6、9...,分片 2 是 1、4、7...,此时 ID 全局有序但分片内无序,执行 WHERE id < 100仍需全量扫描分片内数据,退化为 “内存聚合”; -
不支持跳页:只 加载更多(下一页依赖上一页的锚点),无法直接从第 1 页跳到第 100 页。但可以通过产品设计规避,比如抖音、小红书的列表都是加载更多,用户体验反而更好。
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
现在要查 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 条,不用汇总其他分片。
最早的订单),用普通分页会查 LIMIT 9990, 10,但可以反向查,避开大 offset。
-
反向查锚点:执行 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 扫描。
-
仅适用于最后 1 页:如果要查倒数第 10 页(第 991 页),按这个逻辑无法定位锚点(需要知道第 9900 条数据的 ID),只能查倒数第 1 页; -
数据不能有大量删除:如果中间有大量 ID 被删除(如 ID 5000-8000 都被删了),总数据量变为 7000 条,此时 WHERE id >10 ORDER BY id DESC LIMIT 10拿到的是 7000-6991(正确),但如果删除的是最后 100 条(ID 9901-10000),总数据量变为 9900 条,需要重新计算反向锚点,增加复杂度。
ShardingSphere 的全局排序)。
往期推荐
别再写冗余缓存代码了!Easy-Cache 给你统一解决方案,爽到飞起!
千万级大表如何删除数据?
开源项目|用Java开发一款AI系统,支持文案/PPT/图片/视频生成
SpringBoot 时间轮实现延时任务
Spring Event,贼好用的业务解耦神器!
Postman替代品:一款极简的网页版 API 调试神器!

