拉链维度的性能约束
事实关联拉链维度时必须带业务时间区间条件,只按自然键 join 会让结果行数按版本数成倍放大:一个用户有十二个版本,他的每条订单就会匹配出十二行,金额随版本数虚增。除了写法约束,还要为(自然键、start_date、end_date)建联合索引或排序键,让区间过滤能下推。拉链维表通常不按时间分区,因为它需要被任意历史时间点关联。
基本信息
| Join 条件 | 自然键相等 + 业务时间落在版本区间内 |
|---|---|
| 索引建议 | (natural_key, start_date, end_date) 联合索引或排序键 |
| 分区策略 | 拉链维表通常不按时间分区,需支持任意时点关联 |
| 常见陷阱 | 用 end_date IS NULL 判断当前行,导致索引失效 |
典型使用场景
- 历史口径报表:按订单业务时间关联当时版本,报表可复现
- 当前口径报表:只取 is_current = 1 的版本,先过滤维表再 join
- 大维表调优:为区间条件建索引,避免全表扫描与笛卡尔式放大
- 增量加工:事实与维表都很大时,按日期裁剪后再按区间关联
- 性能回归:把关联行数与事实行数做比对,作为上线前的常规检查
正确关联写法
正确关联写法
-- 必须同时带自然键与时间区间条件
SELECT f.order_id, d.tier
FROM fact_order f
JOIN dim_user d
ON f.user_id = d.user_id -- 自然键(业务键)相等
AND f.order_time >= d.start_date -- 业务时间落在版本区间内
AND f.order_time < d.end_date; -- 闭开区间,避免边界重复命中
-- 只要当前口径时,先裁维表再关联,代价更低
-- JOIN dim_user d ON f.user_id = d.user_id AND d.is_current = 1;
-- 性能校验:关联后行数不应超过事实行数
-- SELECT count(1) FROM fact_order; -- 与上面结果行数对比性能要点
| 要点 | 做法 | 缺失后果 |
|---|---|---|
| 区间条件 | join 中带业务时间与起止日期比较 | 行数按版本数放大 |
| 索引 | 自然键加起止日期联合索引 | 区间过滤无法下推,全表扫描 |
| 当前行判断 | 用 is_current 或远期 end_date | NULL 比较使索引失效 |
| 分区 | 拉链维表不按业务时间分区 | 历史时点关联跨大量分区扫描 |
遗漏区间条件属于最难自查的错误:SQL 能跑通、结果非空、金额看起来也在正常量级,只有把关联行数与事实行数做对比才会发现被放大了。
维表体积很大时,可以在关联前先按业务键裁剪出事实里出现过的成员,再执行区间关联,能显著降低中间结果规模。