第三章:完整性指标——记录缺失率、字段空值率、主键唯一性比例
完整性是数据质量的底线。数据如果缺胳膊少腿,后面的分析全是白搭。我第一次带数据质量项目时,业务方指着报表说「这数字不对」,查了半天,原来是源表丢了 30% 的记录,但大伙儿只看字段没看行数。
这一章咱们就拆开三个最常用的完整性指标:记录缺失率、字段空值率、主键唯一性比例。说句实话,能把这三个用对,日常 80% 的完整性监控就不慌了。
3.1 记录缺失率 —— 你的数据到底少了几行?
定义:期望行数和实际行数之间的差异比例。
举个例子,CRM 系统每天应该同步 10 万条订单,但今天只到了 8 万,记录缺失率就是 20%。
计算公式:
记录缺失率 = (期望记录数 - 实际记录数) / 期望记录数 × 100%
实际计算脚本(Python + SQL 思路):
# 简单写法:对比两天的行数
expected_count = 100000 # 从业务系统元数据拿
actual_count = spark.sql("SELECT COUNT(*) FROM orders WHERE dt = '2025-03-20'").collect()[0][0]
missing_rate = (expected_count - actual_count) / expected_count
print(f"记录缺失率:{missing_rate:.2%}")
这里有个坑。期望记录数从哪来?千万别拍脑袋。我曾经接过一个项目,业务方说「每天应该有 50 万条」,后来发现他们的期望值是基于三年前的系统压测数据算的。我建议,要么从源系统的调度日志拿,要么用历史均值加 3-sigma 做动态基线。
3.2 字段空值率 —— 哪个字段在跟你玩失踪?
记录没丢,但关键字段是空的,这也很要命。字段空值率衡量的是单个字段为空的比例。
计算公式:
字段空值率 = 该字段为空的记录数 / 总记录数 × 100%
计算案例 —— 检查「手机号」字段:
SELECT
COUNT(*) AS total_rows,
SUM(CASE WHEN phone IS NULL OR phone = '' THEN 1 ELSE 0 END) AS null_phone,
ROUND(
SUM(CASE WHEN phone IS NULL OR phone = '' THEN 1 ELSE 0 END) * 100.0 / COUNT(*),
2
) AS null_rate_pct
FROM user_profile
WHERE dt = '2025-03-20';
-- 输出示例
total_rows | null_phone | null_rate_pct
200000 | 8500 | 4.25
4.25% 算不算高?这要看场景。用户注册场景,手机号空值是 0 才行;但匿名浏览日志,手机号为空可能是常态。我习惯为每个字段画一条「容忍线」:核心业务字段 0%,可选字段 < 5%,备注型字段 < 20%。
嗯,这里还要注意「空」的边界。NULL 是空,空字符串 '' 是不是空?空格字符串呢?不同的 ETL 工具处理方式不一样。我建议在数据接入层统一做空值标准化,否则空值率算出来也不准。
3.3 主键唯一性比例 —— 你的数据表有「身份证」吗?
主键重复,是数据质量的大忌。想象一下,订单表里有两条 order_id='123',你说聚合查询时算一笔还是两笔?
计算公式:
主键唯一性比例 = 不重复的主键数 / 总记录数 × 100%
理想的表,这个比值应该是 100%。但凡小于 100%,就有重复记录了。
脚本检查:
-- 先看有没有重复主键
SELECT
COUNT(*) AS total_count,
COUNT(DISTINCT order_id) AS unique_count,
ROUND(
COUNT(DISTINCT order_id) * 100.0 / COUNT(*),
4
) AS uniqueness_pct
FROM transaction_log
WHERE dt = '2025-03-20';
找出具体重复的条数:
-- 找出所有重复的 order_id
SELECT order_id, COUNT(*) AS dup_count
FROM transaction_log
WHERE dt = '2025-03-20'
GROUP BY order_id
HAVING COUNT(*) > 1;
-- 输出示例
order_id | dup_count
TXN-202503-001 | 2
TXN-202503-045 | 3
主键重复的原因我见过几种:
1. 上游重复投递了消息(Kafka 重试就常见)
2. 跑批任务被重复调度
3. 源系统没有做幂等写入
解决办法也简单:入库前加 INSERT OVERWRITE 或者在 ETL 层做 DISTINCT + ROW_NUMBER 去重。
3.4 指标选择:到底用哪个?
这三个指标不是互相替代的关系,而是互补的检查层。我一般这样组合:
| 场景 | 推荐指标组合 | 说明 |
|---|---|---|
| 流水/日志型表(如埋点日志) | 记录缺失率 + 字段空值率 | 重点保证记录不丢,关键维度(如时间戳)不空 |
| 实体/主数据表(如用户表) | 主键唯一性比例 + 字段空值率 | 必须确保主键不重复,核心属性完整 |
| 中间表/汇总表 | 记录缺失率 + 主键唯一性比例 | 保证聚合过程没丢数据,输出主键无重复 |
| 接口/API 输出表 | 三个全上 | 少记录、空字段、重复主键都会导致接口异常 |
我想表达的是,不要贪多。团队初期能把这三个指标跑稳,数据质量就已经超过大多数公司了。
3.5 综合框架:一张图理清三大指标
下面这张 SVG 图帮你快速抓住这三个指标的检查范围和优先级。
这张图给了一个执行顺序:先查主键唯一性,再查记录缺失率,最后查字段空值率。为什么这么排?主键重复最容易导致下游数据膨胀,也最好修;记录缺失影响全局;字段空值虽然烦人,但通常可容忍一段时间。
好了,完整性这块,把行数、空值、主键盯住了,你就抓住了数据质量的命门。动手试试,先选一张你手头的表跑一遍这三个指标,看看有没有意外收获。