事实表外键要建约束吗
数仓事实表保留维度外键列,但通常不建数据库级外键约束。原因是物理外键会在每次写入时校验父表,批量加载与回滚成本明显上升,且加载顺序必须严格串行。引用完整性改由 ETL 校验与例行巡检保障。
基本信息
| 保留内容 | 事实表中的维度代理键列 |
|---|---|
| 约束选择 | 一般不建物理外键,改用加载校验与巡检 |
| 保障手段 | 加载后左连维度找孤儿键、对账、异常表隔离 |
| 加载顺序 | 维表先于事实表,或至少同批次内先维度 |
| 例外 | 小规模或强一致性要求的场景可保留物理外键 |
典型使用场景
- 批量加载事实表:省去逐行外键校验,吞吐显著提升
- 回滚与重跑:没有级联约束牵制,重刷分区更简单
- 跨库场景:事实表与维度表不在同一数据库,物理外键本身不可用
- 质量巡检:把引用完整性检查做成每日任务,替代数据库约束
- 性能调优:避免加载时锁竞争与顺序依赖
引用完整性巡检
引用完整性巡检
-- 找出在维度中找不到对应行的孤儿外键,并统计条数
SELECT f.user_sk, count(1) AS orphan_cnt
FROM fact_order f
LEFT JOIN dim_user d ON f.user_sk = d.user_sk
WHERE d.user_sk IS NULL -- 维表侧为空即为孤儿
GROUP BY f.user_sk
ORDER BY orphan_cnt DESC;
-- 巡检放在加载之后、对外可见之前执行
-- 命中孤儿键时:先隔离分区,再定位是编码缺失还是同步延迟保障方式对比
| 方式 | 优点 | 代价 |
|---|---|---|
| 物理外键约束 | 数据库级保证,最严格 | 写入校验开销大,加载顺序受限 |
| ETL 加载校验 | 灵活,可按批次拦截 | 依赖实现质量,漏做就无保障 |
| 日常巡检 | 可发现历史遗留问题 | 发现滞后,脏数据可能已对外 |
| 完全不校验 | 无额外成本 | 孤儿键静默存在,报表出现空维度 |
不建物理外键不等于不要求完整性,只是把校验位置从数据库挪到了加载流程。校验链路要有明确的失败处理:拦截、隔离还是落默认成员,必须事先约定。
维表加载带过滤条件(例如只同步有效状态记录)时,事实侧引用的历史成员会变成孤儿键。维表过滤规则变更必须同步评估事实侧的引用影响。