3.4 · 反规范化
目标: 知道何时有意打破范式,并接受取舍。
反规范化是什么
故意把冗余引入规范化模式以加快读取或简化查询 —— 通常通过存聚合值、去规范化查找或摘要。
为何反规范化
| 原因 | 例子 |
|---|---|
| 性能 | 日报需昂贵 JOIN;每小时存结果 |
| 报表 | OLAP / 数据仓库层偏好宽表做分析 |
| 降低复杂性 | 前端查询变简单 |
| 缓存 | 避免重算昂贵聚合 |
代价
| 取舍 | 详情 |
|---|---|
| 更新异常 | 反规范副本可能漂离源头 |
| 储存 | 重复数据占盘 |
| 维护 | 需触发器 / 计划任务保副本新 |
反规范化例子
例 1 · 在订单上存顾客名快照
规范化:
Order(order_id, customer_id, …)
Customer(customer_id, name)1
2
2
要生成订单收据就 JOIN 两表。顾客改名后过去收据都显示新名。
反规范化:
Order(order_id, customer_id, customer_name_at_order_time, …)1
利:收据总显示当时名。弊:数据重复 —— 顾客修正笔误,过去订单仍显笔误。
例 2 · 预算每日总额
规范化:每次报告都从百万行 Sales 算 SUM(sale_amount)。
反规范化:夜间任务填 DailyTotals(date, total_sales)。报告查这小表即时。
例 3 · 物化视图(进阶)
物化视图是物理存的反规范缓存;按计划刷新。
反规范化步骤(要刻意做)
- 剖析慢查询,确认规范化是瓶颈。
- 选能帮上忙的最小反规范化。
- 明确文档记冗余。
- 加刷新策略(触发器、任务、应用代码)。
- 监控漂移。
学生常见错误
- 规范化前先反规范化 —— 模式凌乱,理解不到取舍。
- 忘了把缓存副本同步。
- 反规范化过度 —— 为微小收益复制一切。
考试式题目
题(5 分): 校报系统每次老师查班级总结都跑
Student、Class和 12 个月Score记录的 JOIN。查询慢了。(a) 建议反规范化方法。 (b) 讨论方法的一个风险与一个缓解。
参考答案:
(a) 创建反规范化总结表:
sql
CREATE TABLE ClassSummary (
class_id VARCHAR(10),
month VARCHAR(7), -- '2026-06'
subject VARCHAR(30),
avg_score DECIMAL(5,2),
PRIMARY KEY (class_id, month, subject)
);1
2
3
4
5
6
7
2
3
4
5
6
7
夜间任务从 Student 与 Score 预聚合填此表。老师的「班级总结」视图查这张小且带索引的表。
(b) 风险:分数在夜间刷新后被改,则总结陈旧 —— 老师看到昨日数字而非今日。
缓解:分数改时立刻触发更新总结;或在考试季更频繁跑刷新任务(如每小时)。
关键要点
- 反规范化拿盘空间 + 复杂性换速度。
- 总用剖析证明合理。
- 预先规划刷新策略。
➡️ 下一节:3.5 ER → 表