跨库分页查询
2020年某电商平台的订单列表接口,用户翻到第100页时,数据库CPU突然飙升到95%,整个服务瘫痪了5分钟。
技术团队排查后发现:订单表分到了8个库,每个库3000万条记录。查询第100页(每页20条)时:
这个SQL在每个分片上都要扫描2000条记录才能返回第20条,8个分片累计扫描16000条。
随着页数增加,每个分片需要扫描的记录数线性增长,最终导致数据库被打挂。
这是一个典型的"深度分页"问题。
【面试官手记】
跨库分页是分库分表后最常见的问题之一。我面试过的候选人里,能说清楚"分页为什么会慢"的不超过40%,能说出"解决方案"的不超过20%。跨库分页的关键是避免深度扫描。
一、分页查询的原理 🔴
1.1 单库分页原理
1.2 跨库分页原理
1.3 面试追问
面试官:为什么分页越深越慢?
候选人:因为数据库需要扫描前面的记录才能定位到目标记录。
面试官:怎么解决深度分页问题?
候选人:三个方案:
一是游标分页:用主键或时间戳作为游标,不扫描中间记录
二是ES搜索:ElasticSearch天然支持分页
三是限制最大页数:超过阈值返回空
【面试官心理】
跨库分页的追问通常很深入。能回答出"游标分页"的候选人,说明知道基本原理;能说出"ES搜索"的候选人,说明知道进阶方案。
二、游标分页方案 🔴
2.1 原理
2.2 代码实现
2.3 跨库游标分页
三、ES搜索方案 🟡
3.1 原理
3.2 ES代码实现
四、限制最大页数 🟡
4.1 方案
4.2 前端引导
五、生产避坑 🟡
5.1 跨库分页的五大坑
坑1:深度分页导致雪崩
坑2:游标分页不支持跳页
坑3:跨库排序不一致
坑4:数据倾斜
坑5:分页数据量不确定
5.2 方案对比
六、真实面试回放 🟡
面试官:分库分表后怎么查询?分页怎么做?
候选人(小张):查询分两种:
一是分片键查询。查询条件包含分片键,直接路由到对应分片。
二是非分片键查询。需要查询所有分片,合并结果。
分页的话:
一是浅分页。用OFFSET和LIMIT,页数不深时可以用。
二是游标分页。用上一页最后一条记录的ID作为起点,性能恒定。
面试官:游标分页怎么实现跨库?
小张:三个步骤:
一是每个分片执行游标查询:WHERE shard_key = ? AND id < lastId ORDER BY id DESC LIMIT N。
二是合并所有分片的结果。
三是合并后再排序,取前pageSize条。
面试官:游标分页的缺点是什么?
小张:两个缺点:
一是不支持跳页。用户从第5页不能直接跳到第10页。
二是需要上一页的游标。无法直接获取第N页。
【面试官手记】
小张这场面试的亮点:
知道查询分两种:分片键和非分片键
知道分页方案:OFFSET和游标分页
知道跨库游标分页的实现步骤
跨库分页是P6工程师必备技能,能完整回答的候选人,说明有分库分表经验。
跨库分页的核心是避免深度扫描。记住三个要点:
- OFFSET分页:页数不深时使用
- 游标分页:深度分页用,性能恒定
- ES分页:全文搜索场景使用
没有完美的分页方案,只有最适合业务场景的方案。