知识全景图/ 软件工程与系统/ 数据库生产治理/ 如何设计数据库分库分表与数据再平衡

如何设计数据库分库分表与数据再平衡

不要先背 hash 和 range;先解释“按 entry_id 分片后,用户查本月账单为什么要广播所有库”

这一页只解决一个问题: 单库快到边界时,业务表怎样拆,路由怎样设计,旧数据怎样搬,扩容时怎样不写错库。分库分表不是把表拆小,而是把业务访问模式写进数据布局。
一、事故:按 entry_id hash 后,查询全变广播

Web 记账系统把 ledger_entriesentry_id % 4 分成 4 个库。写入均匀了,但用户查“本月账单”时不知道这个用户的数据在哪个库,只能 4 个库都查再合并排序。

bad shard key: shard = entry_id % 4 common query: WHERE tenant_id = ? AND occurred_at BETWEEN ? AND ? result: query all shards merge and sort in application
看似解决实际失败逼出的设计
写入均匀高频查询变广播shard key 要服务访问模式
表变小跨 shard 排序分页变复杂常见列表必须带路由键
扩容简单旧路由和新路由可能同时写路由表要有版本和校验
二、分片前只问 6 个问题
问题例子
是不是真的到了分片边界先排除坏 SQL、缺索引、报表扫明细、归档缺失
最高频查询按什么找数据账目通常按 tenant_id / ledger_id / month 查
哪些事务必须在一个库内新增账目、分类校验、预算占用最好同 shard
哪些查询允许异步全站统计、运营报表不要继续打分片 OLTP
超级租户怎么办tenant_id 分片后仍可能有大租户热点
扩容迁移时旧路由怎么拒绝route_version、slot ownership、旧 shard 写保护
三、最小路由模型
shard_map - route_version - slot_start - slot_end - shard_id - status: active | moving | retired - updated_at shard_ownership - shard_id - slot_id - route_version - writable
吸收点: 不要只在代码里写 hash 函数。真正的分片要有可变更、可审计、可拒绝旧版本的路由事实。
四、分片设计只守 4 条边界
边界错误做法更稳做法
shard key按 entry_id 均匀写按 tenant_id / ledger_id 让高频查询和事务共址
全局 ID继续用单库自增号段、Snowflake、ULID 或带定位能力的 ID
跨 shard 查询在线广播所有库限制、异步化,或转到搜索 / 报表 / OLAP
再平衡停服搬库历史复制、增量追平、影子校验、灰度切路由
关键判断: 如果大量高频写入都需要跨 shard 事务,优先怀疑 shard key 选错,而不是先上复杂 2PC。
五、用 6 个样本证明分片可信
样本通过标准
查某租户本月账单命中单 shard,不广播
新增账目并占用预算账目、分类、预算在同 shard 内完成
运营查全站 Top 分类不扫所有 shard 明细,走异步报表
旧应用拿旧 route_version 写入被拒绝或转发,不静默写错库
迁移期间持续新增账目新 shard 最终记录数和金额汇总一致
超级租户写入放大能识别热点并迁出或二级分片
六、下一步只按分片风险下钻
如果核心问题是租户边界
权限、审计与敏感数据治理里的租户隔离与资源边界。
如果核心问题是在线搬库
如果核心问题是慢查询
如果想看 DBMS 内部分片
总结: 分库分表最重要的不是 hash,而是 shard key、路由版本、共址事务、跨 shard 查询边界和再平衡证据。只要用户最常见查询还要广播所有库,分片设计就还没对。