用空值表达未知是什么
这个反模式指维度外键留空、属性用 NULL 表示「未知」或「不适用」。后果很直接:NULL 不参与相等比较,join 会静默丢行;聚合函数忽略 NULL,报表总数对不上;分区裁剪与外连接行为也会因此偏离预期。正确做法是用显式的未知成员行(如代理键 -1)和语义化默认值(UNKNOWN、N/A)表达未知,把 NULL 留给真正无值的语义,并对未知占比做监控。
基本信息
| 主要问题 | join 丢行、聚合漏统计、裁剪失效 |
|---|---|
| 治理手段 | 维度侧建未知成员行,事实侧挂该键 |
| 属性默认值 | UNKNOWN、N/A 等语义化常量,不用空串 |
| NULL 保留范围 | 仅用于真正无值的语义,如未填写的备注 |
| 监控 | 按表统计维度键空值与未知占比,设阈值告警 |
典型使用场景
- 事实加载时维度键解析失败:先落未知成员键,等维度到位后回刷
- 维表属性缺失:用 UNKNOWN 成员或 N/A 显式表达,而不是留空
- 数据质量巡检:每日监控各事实表维度键的空值与未知占比
- join 排查:报表行数少于事实行数时,优先查外键空值与 NULL 关联
- 跨系统归一:对方字段缺省值有 NULL、空串、-1 三种写法,入仓时统一
- 外连接修正:需要保留未匹配行时用外连接加未知成员,不用 NULL 兜底
空值影响与检测
空值影响与检测
-- 1) NULL 参与 join 会直接丢行
SELECT count(1) FROM fact_order WHERE user_sk IS NULL;
-- 2) NULL 与任何值比较都不成立,包括 NULL = NULL
-- SELECT 1 WHERE NULL = NULL; -- 返回空,不是真
-- 3) 聚合忽略 NULL,分母与行数会悄悄变小
SELECT count(user_sk) AS cnt_not_null,
count(1) AS cnt_all,
count(1) - count(user_sk) AS null_cnt
FROM fact_order;
-- 4) 用未知成员键替代空值后,关联不再丢行
-- INSERT INTO dim_user VALUES (-1, 'UNKNOWN', 'UNKNOWN', -1);表达方式对照
| 场景 | 错误做法 | 推荐做法 |
|---|---|---|
| 维度键解析不到 | 外键留 NULL | 挂未知成员键 -1,并回刷 |
| 属性值未知 | NULL 与空串混用 | 统一 UNKNOWN 常量 |
| 属性不适用 | NULL 表示不适用 | 独立的 N/A 成员,语义可区分 |
| 数值缺失 | 填 0 | NULL 表示缺失,0 是真实值需区分 |
| 日期缺失 | 填当天或空串 | 未知日期成员键,避免污染时间口径 |
把缺失的数值填 0 与用 NULL 表示缺失是两种不同错误:一种让平均值变小,一种让行数变少。关键不是选哪种,而是缺失必须有显式表达且能被统计,否则问题永远只在业务对账时才暴露。