前言
分库分表的落地不仅是技术方案的设计,更考验从单库到分片的全链路适配能力。
很多面试中,面试官不仅问怎么分,更关注分完怎么用。
开发会不会踩坑?一致性怎么保?查询性能怎么扛住?运维怎么应对变化?
今天围绕开发适配、数据一致性、查询优化、运维调整四个核心内容,结合订单表场景(日均 100 万单,按用户 ID 哈希分 8 库 16 表),拆解落地细节,每块内容后面都附有面试时的加分表述,帮你把实践经验转化为面试亮点。
单库时代的随手写 SQL在分库分表后会变成性能炸弹:漏掉分片键的查询可能扫全表,跨分片 join 会让响应时间翻倍。
开发适配的核心是:让每个操作都先想清楚分片键在哪里。
create_time条件,漏掉user_id,导致 16 张表全扫描,耗时从 10ms 飙到 500ms。where user_id=123 and create_time > '2025-08-04'),中间件直接路由到目标表;count(*)无分片键时,改为各分片查 count + 应用层累加)insert按user_id%16定位表);user_id%16分成 10 组,每组写对应表),效率提升 80%。我们订单表按 user_id 分了 16 片后,初期开发常漏掉分片键写 SQL,导致全表扫描。我牵头做了两件事:一是制定SQL 必须包含分片键的规范,用 ShardingSphere 的 SQL 审计功能拦截违规查询,开发环境直接报错,一周内就把全表扫描的 SQL 从 30% 降到了 0;二是梳理高频操作模板,比如批量创建订单时,要求先按 user_id 分组再批量写入,还写了工具类自动处理分组逻辑。后来团队慢慢养成了写 SQL 先想分片键的习惯,线上查询延迟平均降了 60%。
分库分表后,一个业务操作跨多分片成了常态 : 创建订单可能涉及订单表(分片 A)和库存表(分片 B),稍有不慎就会出现订单创建成功但库存没扣的不一致。核心要解决全局 ID 不冲突和跨分片事务不丢数据两个问题。
Try阶段预扣库存、冻结订单,Confirm阶段确认生效,Cancel阶段回滚;我们初期用自增 ID 做订单号,很快发现分表后 ID 重复,导致支付回调出问题。我调研后选了雪花算法,特意在 ID 里加了分片标识位,这样查问题时从 order_id 就能反推在哪个表,排查效率提升了一倍。分布式事务这块,下单场景我们试过 2PC,但发现性能太差(协调者等待所有分片响应,耗时增加 300%),后来换成了 TCC: 因为下单对一致性要求高,但可接受 1 秒内的最终一致,TCC 的 Try/Confirm/Cancel 逻辑刚好适配,而且能避免全局锁。普通场景比如物流单创建,就用本地消息表,毕竟没必要为非核心流程扛 TCC 的开发成本。
分表后查询的核心矛盾是数据分散但需聚合结果: 分页查第 100 页可能扫全表,多条件查询没索引会超时。优化的关键是减少跨分片扫描,让查询尽可能落在单分片。
limit 10000,10查第 1001 页,16 张表各扫 10010 条,聚合后耗时 2 秒 +。select * from order where user_id=123 order by create_time desc limit 10,记录最后一条的create_time=xxx和order_id=456;select * from order where user_id=123 and (create_time < xxx or (create_time=xxx and order_id < 456)) order by create_time desc limit 10;user_id定位分片,建组合索引(user_id, create_time, status),让查询走索引扫描;order_index(按create_time分表),存order_id和分片信息,先查索引表得分片列表,再逐个查详情,比全表扫描减少 90% 工作量。分页查询我们踩过一个大坑:运营要查第 1000 页的订单,用 limit 10000,10 直接把数据库打挂了。排查发现是每个分片都在扫全表,我牵头改成了游标分页 : 用 create_time+order_id 做标记,本质是把 offset 跳过变成条件过滤,虽然前端不能直接跳页,但运营场景里上 / 下一页足够用,改造后 1000 页查询耗时从 2 秒降到了 80ms。多条件查询方面,我们区分了有分片键和无分片键:前者靠组合索引压到单分片内查,后者建了二级索引表,比如查全国大额订单时,先通过索引表定位到 3 个分片,再查详情,比全扫 16 个分片快多了。
数据量和业务不会一成不变:半年后订单量翻倍需扩容,业务调整要改分片键。运维的核心是在不影响业务的前提下,让分片策略跟上变化。
order_16到order_23),中间件配置新旧分片共存;user_id%16),读请求仍走旧表;user_id分片,因按地区统计订单需频繁跨分片,改为地区 + user_id复合分片。order_region_0到order_region_15),旧表保留;我们订单表从 8 片扩到 16 片时,最担心影响线上写入。我设计了双写 + 灰度迁移方案:先让新表和旧表同时写入,读请求还走旧表,这样即使迁移出问题,回滚也方便。迁移时用工具按 user_id 分批导,每批 10 万条,导完就校验,发现 3 处数据不一致(都是旧表的更新没同步),当场修复了。整个过程没停服,写入性能只降了 5%,业务完全没感知。后来要改按地区分片,我们没直接换,而是新增了一套分片表双写,让新业务用新表,老业务慢慢切,用了 3 个月平稳过渡,没出一次故障。
开发适配要盯住分片键,一致性保障要选对方案,查询优化要避免全扫描,运维调整要平滑过渡。比起怎么分,“怎么用得稳、用得顺更考验工程能力,毕竟技术最终要服务于业务查询和用户体验。