贴吧式
冗余字段到底该不该进主表?反范式化的边界,DBA 和开发到底怎么吵
帖子正文与楼层回复。
楼主 陈砚舟-902
数据库设计反范式化冗余字段JOIN优化DBA
背景
做了 3 年 DBA,被开发问得最"理直气壮"的一类需求是:"这个字段就为读方便一点,冗余到主表里吧,省得 JOIN。" 典型场景:订单主表 t_order 上挂着 merchant_name(商家名)、status_text(状态中文文案)、region(收货省份),而它们其实分别来自商家表、状态字典表、地址表。开发说"少 JOIN 一次,列表页快 20ms";我说"商家改名你就得回刷几千万行"。这事没有标准答案,但社区里我几乎没看到有人把边界系统讲清楚,想借这个帖摊开聊聊。
常见分歧 / 几种做法
- 纯范式党:能 JOIN 就 JOIN,绝不在主表存冗余,"一物一处存、处处一致"。读多写少的 B 端后台基本都能接受。
- 务实反范式党:高频读、极少变的字段(商家名、状态文案)冗余进主表或冗余成宽表,用"写时同步 + 异步补偿回刷"兜一致性。C 端列表页、Feed 流、搜索快照几乎都这么干。
- 中间派:主表只冗余"几乎不变 + 极高频读"的字段(如状态文案),易变字段(商家名、地址)走读模型 / 缓存 / 离线宽表,主表保持干净。
我的倾向与理由
我站中间派,判据就一条:这个字段"被改"的概率 × 改动时"回刷的代价",是否压得过低频读的收益。 状态文案、创建时间这类冗余进去几乎零成本;商家名、地址这类一改就要动历史数据,我宁可让读端去拼,也不让主表背。理由有二:一是主表是"事实源",冗余字段一旦和源表漂移,排查"为什么这条数据和商家表对不上"比省那 20ms 贵得多;二是回刷本身是危险操作——大表 UPDATE 锁行、binlog 放大、从库延迟,往往比当初省下的 JOIN 更伤性能。如果一定要冗余,我会要求:明确 owner、有异步对账/回刷任务、把"以哪张表为准"写进文档。
想听大家怎么选
- 你们团队判"该不该冗余"的硬标准是什么?有没有量化过"读 QPS / 变更频率"的门槛?
- 真冗余了,历史数据回刷你们用同步刷、binlog 订阅、还是离线任务?大表回刷踩过什么坑(锁、延迟、脏读)?
- 状态文案这种"字典类"冗余,你们直接冗余进表,还是应用层 map 一下?
贴具体表结构和 QPS 更好聊,欢迎对线。
赞 0 · 收藏 0 · 楼层 0
楼层
#1
作者
楼层正文
还没有人回复。