首页/数据/数仓建模速查/反模式:用空值表达未知
建模基础69 条

反模式:用空值表达未知

维度外键均为空、属性用 NULL 表达未知,会让 join 丢行、聚合失真;用未知成员行与语义化默认值显式表达。

数仓建模速查数据更新于 2026-10-13

用空值表达未知是什么

这个反模式指维度外键留空、属性用 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 成员,语义可区分
数值缺失填 0NULL 表示缺失,0 是真实值需区分
日期缺失填当天或空串未知日期成员键,避免污染时间口径
把缺失的数值填 0 与用 NULL 表示缺失是两种不同错误:一种让平均值变小,一种让行数变少。关键不是选哪种,而是缺失必须有显式表达且能被统计,否则问题永远只在业务对账时才暴露。

易错点

  • NULL 参与 join 静默丢行:报表行数少一截且不报错,往往到对账才发现
  • 用 NULL = NULL 做去重或比较:条件恒不成立,去重与匹配全部失效
  • 缺失数值填 0 与 NULL 混用:平均值与总数同时失真,两个口径互相污染
  • 空值率不做监控:上游主数据衔接断了一周,报表少算却无人知晓
  • 属性用空串表示未知:空串与 NULL 并存,筛选条件要写两遍还容易漏

数据来源与参考

  • 维度建模反模式:空值处理
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌