在智慧物流园区“数港”的收货中心,经验丰富的验货员司哲每天都要面对从各地涌来的数据包裹。这些包裹看似五花八门,其实每一件都承载着重要信息——它们是一个个数据行,即将进入仓库,成为训练 AI 模型的原料。司哲深知一个道理:如果包裹在运输途中丢了零件、贴错了标签甚至被掉包,那么仓库建得再漂亮,最终生产出来的模型也会“营养不良”。于是,他设计了一套严格的收货验收流程:塑封检查、单号扫描、物品分类、限重测量、货单比对、开箱抽检,确保每一件包裹都以完整、准确的状态入库。 这套验收流程,正是 AI 数据管道工程中大名鼎鼎的“数据完整性检查”。它像一道闸门,把有缺陷的数据拦截在系统之外,守住数据质量的底线。本文将通过司哲在数港的一天,带你理解完整性检查的基本概念、核心方法、工程实践与异常处理。

岗位关联

掌握数据完整性检查,是数据工程师与质量监控工程师的看家本领。它让你在 AI 项目中提前拦截脏数据,避免“垃圾进、垃圾出”的灾难,是构建可靠数据管道的基石技能。

目录
  1. 可视化演示
  2. 完整性概述
  3. 非空与唯一性
  4. 类型与格式校验
  5. 值域与业务规则
  6. 引用完整性
  7. 校验和与哈希
  8. 工程实践
  9. 异常处理监控
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

动态演示数据完整性检查方法的核心机制,通过总览/传输/转换/输出四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

数据完整性检查方法:数据完整 数据完整性的四类约束体系 主外键与唯一约束的检查实现 核心机制可视化 数据完整性检查方法整体架构与关键组件

完整性概述

数港收货中心的墙上贴着一张泛黄的《收货验收单》,第一行写着“完整性”三个大字。老员工司哲对新人说:别把它想复杂了,完整性的意思就一句话——“该有的东西都在,该对得上号的对得上号”。你收到一个包裹,里面没货是空箱,这是缺货;箱子上贴的运单号和另一件重复,这是错乱;货单写的是“电子元件”,打开却是液体,这是张冠李戴。这些通通叫“不完整”。

在数据世界里,“包裹”是一行行记录,“货”是字段里的具体值。数据完整性(Data Integrity)指数据在其生命周期中保持准确(Accuracy)、一致(Consistency)与可信赖的程度。AI 数据管道里,完整性检查就是在数据入库、训练之前执行的一系列自动化验证,把“不完整”的行李拦截在门外。

业界将完整性拆成四个维度:实体完整性(Entity Integrity)要求主键非空且唯一;引用完整性(Referential Integrity)要求外键能对应到有效主键;域完整性(Domain Integrity)约束字段的类型、格式和取值范围;用户定义完整性(User-defined Integrity)承载业务规则。检查频次取决于管道节奏:批处理管道每天夜间全量校验,流式管道在事件进入时实时校验,还有按表变更触发的增量校验。衡量整体质量,最常用的指标是完整性通过率:

司哲常说,四个维度就像验收单上的四个手指印,缺一个都按不下。测量“完整不完整”,最终就看这个通过率——今天 99.2%,明天 97.5%,趋势一掉,就知道哪个关卡松了。

Integrity Rate=NpassNtotal×100%\text{Integrity Rate} = \displaystyle\frac{N_{\text{pass}}}{N_{\text{total}}} \times 100\%
通过率 = 通过全部检查的记录数 ÷ 总记录数 × 100%。它是数据管道体检报告上的“体温值”。
  1. 总记录数 $N_{\text{total}}$本批次进入检查的所有数据行(包裹)数量,作为分母。
    NtotalN_{\text{total}}
  2. 通过记录数 $N_{\text{pass}}$通过全部检查规则的记录(完好包裹)数量,作为分子。
    NpassN_{\text{pass}}
  3. 乘以 100%把比值换算成百分比,便于设定阈值和对比趋势。
    NpassNtotal×100%\frac{N_{\text{pass}}}{N_{\text{total}}} \times 100\%

非空与唯一性

司哲验收的第一道关卡叫“塑封检查”,由人称胖姑的检验员负责。她用手一摸,空箱子直接丢回传送带;第二道关卡是“单号扫描”,扫码枪扫过运单条码,机器发出“嘀”声,同一个单号出现两次就亮红灯。两道关卡看似简单,却拦住了一批批“糊弄事”的包裹。

对应到数据库,塑封检查就是非空校验(NOT NULL):主键字段、业务关键字段(如 user_id、order_id)不允许为空。单号扫描就是唯一性校验(UNIQUE):同一列里不允许出现重复值。空值和重复值是最常见、也最容易破坏下游分析正确性的两类脏数据。AI 特征工程中,一个空值可能导致模型推断失败,一个重复 ID 会让样本权重失衡。

实践中,非空率用缺失比例度量,唯一性用 COUNT(*) 与 COUNT(DISTINCT col) 对比检测重复。SQL 中 WHERE col IS NULL 可以快速定位缺失行,GROUP BY col HAVING COUNT(*) > 1 可以揪出重复组。缺失率公式:

胖姑摸空箱、扫码枪查重复,这两道关卡守住了数据的最底线。司哲说,一个连“非空”和“唯一”都做不到的表,后面再花多大力气清洗都是亡羊补牢。

NULL Rate=COUNT(∗)−COUNT(col)COUNT(∗)×100%\text{NULL Rate} = \displaystyle\frac{\text{COUNT}(*) - \text{COUNT}(col)}{\text{COUNT}(*)} \times 100\%
缺失率 =(总行数 − 该列非空行数)÷ 总行数 × 100%。数值越大说明“空壳包裹”越多。
  1. 总行数 COUNT(\*)表中全部记录数,反映包裹总量。
    COUNT(∗)\text{COUNT}(*)
  2. 非空行数 COUNT(col)该列中非 NULL 值出现的次数,即完成塑封的包裹数。
    COUNT(col)\text{COUNT}(col)
  3. 差值作分子总数减去非空数,就是缺失值的个数。
    COUNT(∗)−COUNT(col)\text{COUNT}(*) - \text{COUNT}(col)
  4. 除以总数再乘 100%得到缺失率,用于评估该字段的完整程度。
    COUNT(∗)−COUNT(col)COUNT(∗)×100%\frac{\text{COUNT}(*) - \text{COUNT}(col)}{\text{COUNT}(*)} \times 100\%

类型与格式校验

传送带第二站是“物品分类登记”,由老会计负责。老会计眼神不好但心细,看到运单上写着“精密仪器”,打开箱子看到的却是瓶瓶罐罐的液体,他立刻扣下。他还要较真日期格式:单上写“25年3月1日”、系统里写"2025-03-01",他必须统一成一种写法才放行。

这就是类型校验和格式校验。类型校验确认字段值匹配预期的数据类型(整型、浮点、字符串、日期、布尔);格式校验确认字符串符合约定的模式,如手机号 11 位、邮箱含 @、日期符合 ISO 8601。AI 管道中,类型/格式错误会导致特征工程崩溃,例如把数值列当成对象参与计算,模型训练直接报 TypeError。

实践中常用两种手段:一是尝试类型转换(CAST),转换失败即标记异常;二是正则表达式(Regular Expression)匹配格式,如 ^\d{4}-\d{2}-\d{2}$ 匹配 yyyy-MM-dd。转换的成功率可以量化格式健康度:

老会计的较真,在数据世界里就是一行行 CAST 和正则。司哲打趣说,别嫌他烦,等模型训练报出 TypeError: unsupported operand 时,你就知道老会计的功劳了。

Cast Rate=NokNtotal×100%\text{Cast Rate} = \displaystyle\frac{N_{\text{ok}}}{N_{\text{total}}} \times 100\%
转换成功率 = 成功转换为目标类型的行数 ÷ 总行数 × 100%。越接近 100%,说明类型越干净。
  1. 成功转换记录 $N_{\text{ok}}$将字段值尝试转换为目标类型时成功的行数,类似老会计核对无误的登记单。
    NokN_{\text{ok}}
  2. 总记录 $N_{\text{total}}$参与本次转换测试的全部行数。
    NtotalN_{\text{total}}
  3. 比值转换成功率,衡量类型统一的执行力度。
    NokNtotal\displaystyle\frac{N_{\text{ok}}}{N_{\text{total}}}

值域与业务规则

传送带第三站“限重测量”由尺子蔡负责。他手里一把尺、一杆秤,包裹超过 30 千克、长宽高超限,一律拦下。但他不只是量尺寸——生鲜包裹要求 24 小时内送达,保温箱温度记录必须正常,这是“业务规则”。比如电商平台规定“单价不能为负数”“钻石会员折扣不低于 7 折”,都属于业务规则校验。

值域校验(Range Check)确保数值落在合理区间,如年龄 0-120、分数 0-100、单价非负。业务规则校验(Business Rule Validation)则编码领域知识,如“订单金额 = 商品金额 + 运费”“会员等级与折扣率匹配”。这类检查在数据从生产库同步到数仓时常被忽略,却是业务分析结果可信的关键。数据库通过 CHECK 约束实现,管道中则用规则引擎或条件表达式逐步执行。

对每个字段定义上下界 $(L, U)$,判定记录是否合法:

尺子蔡的量尺量的是数值边界,他脑子里的业务手册管的是“合理”二字。数据管道里的 CHECK 约束,就是被代码化的那把尺子。

valid={1if L≤x≤U0otherwise\text{valid} = \begin{cases} 1 & \text{if } L \le x \le U \\ 0 & \text{otherwise} \end{cases}
合法记 1,越界记 0。把业务边界翻译成数学判定,机器才能自动执行“限重测量”。
  1. 字段值 $x$待校验的单个样本值,如某条订单的金额。
    xx
  2. 下界 $L$ 与上界 $U$业务允许的最小值和最大值,如分数区间 $[0,100]$。
    L≤x≤UL \le x \le U
  3. 输出 0 或 1在界内输出 1(放行),越界输出 0(拦截)。
    valid=0\text{valid} = 0

引用完整性

传送带终点的“货单比对”是司哲最看重的关卡。每个包裹的送货单上都写着“发货仓:华东三号仓”,而仓储系统的仓单表里必须能查到这张仓单。查不到,就是“孤儿货”——不知道从哪儿来的,自然不敢往货架上放。

这就是引用完整性:子表(外键表)中的每个外键值,必须在父表(主键表)中存在对应的主键记录。订单表的 customer_id 必须在客户表里有记录;订单明细表的 order_id 必须能追溯到订单主表。缺失关联即“孤儿记录”,是报表对不上账、联表查不到数据的主要根源。

检测方法是对两张表做关联查询,找出“连不上”的行。匹配率衡量关联健康度:

没有货单比对的仓库,终有一天会堆满来路不明的“孤儿货”。司哲说,数据表和表之间,靠的就是这种“货单对仓单”的信任链。

Match Rate=∣A∩B∣∣A∣×100%\text{Match Rate} = \displaystyle\frac{|A \cap B|}{|A|} \times 100\%
匹配率 = 能成功关联的记录数 ÷ 子表外键记录总数 × 100%。低于 100% 说明存在孤儿记录,必须深查。
  1. 子表集合 $A$子表中待匹配的外键值集合,如所有订单的 customer_id。
    AA
  2. 父表集合 $B$父表中存在的主键值集合,如客户表的全部 id。
    BB
  3. 交集 $A \cap B$能成功关联的记录数,即“货单对得上仓单”的数量。
    ∣A∩B∣|A \cap B|
  4. 比值匹配率,越接近 100% 关联越可靠。
    ∣A∩B∣∣A∣\displaystyle\frac{|A \cap B|}{|A|}

校验和与哈希

每天下班前,司哲还有一道例行的“开箱抽检”:随机拆开几件包裹,拿出货物清单,当着送货员的面重新清点比对。清单和实物一字不差,才在验收单上盖章。他的老搭档“哈希”是个计算器,能把整箱货物的状态压缩成一串数字指纹——只要货物被动过,指纹立刻就变。

数据领域的对应物是校验和(Checksum)与哈希(Hash)。校验和对数据块做简单计算(如累加取模)获得短码;哈希函数(如 SHA-256)把任意数据映射为固定长度的“指纹”。传输前后分别计算指纹并对比,一致则说明内容未被篡改。AI 管道中,模型文件、特征快照、训练集版本都会用哈希建立指纹,防止“上线模型被偷偷换过”这类安全事故。

生产环境常用 SHA-256 对文件、消息或表行做指纹提取。以整表为例,先按约定顺序拼接关键列,再计算哈希:

司哲把开箱抽检交给哈希,省了大力气:不用逐件拆箱,拿指纹一比对,谁的货被调包一目了然。数据管道的上下游之间,也靠这枚“数字指纹”建立信任。

hdata=SHA256(concat(c1,c2,…,cn))h_{\text{data}} = \text{SHA256}(\text{concat}(c_1, c_2, \dots, c_n))
数据指纹 = SHA256(按约定顺序拼接所有字段后的字符串)。内容一变,指纹即变。
  1. 拼接函数 concat把多个字段按约定顺序拼成一个字符串,相当于把货物清单列成一行。
    concat(c1,c2,…,cn)\text{concat}(c_1, c_2, \dots, c_n)
  2. 哈希函数 SHA256对拼接结果计算 256 位摘要,生成固定长度指纹。
    SHA256(⋅)\text{SHA256}(\cdot)
  3. 指纹 $h_{\text{data}}$数据内容对应的指纹值,内容任何改动都会导致指纹改变。
    hdatah_{\text{data}}

工程实践

随着数港业务翻番,人工验收扛不住了。司哲改造流水线:每道关卡装上扫码器和传感器,数据实时汇总到一块大屏。他自己站在屏前盯着“今日验收通过率”曲线,偶尔抽查报警项。

工程上,完整性检查要产品化、工具化。常见开源框架如 Great Expectations、dbt tests、Apache Griffin 提供声明式检查规则和自动报告。关键是检查策略的取舍:全量检查准确但昂贵,抽样检查便宜但有盲区。一般主键、外键等关键字段全量查,数值分布类指标抽样查趋势。抽样量用统计公式估算,在 95% 置信水平下:

流水线改造后,司哲从“搬货工”变成了“盯盘手”——检查不是越多越好,而是在成本与风险之间找平衡,这与设计 AI 数据管道是同一个道理。

n=Z2⋅p⋅(1−p)e2n = \displaystyle\frac{Z^2 \cdot p \cdot (1-p)}{e^2}
最小样本量 = 置信系数² × 预估异常率 ×(1−预估异常率)÷ 误差容忍²。它告诉你“抽多少条才足够可信”。
  1. 置信系数 $Z$95% 置信水平对应 $Z \approx 1.96$,代表统计把握度。
    Z≈1.96Z \approx 1.96
  2. 预期比例 $p$预估的数据异常率,无历史数据时可先取 0.5(最保守)。
    p=0.5p = 0.5
  3. 误差容忍 $e$可接受的抽样误差,如 0.02 表示误差不超过 2 个百分点。
    e=0.02e = 0.02
  4. 计算结果 $n$所需最小样本量,如 $1.96^2 \times 0.5 \times 0.5 / 0.02^2 \approx 2401$。
    n=1.962×0.5×0.50.022≈2401n = \frac{1.96^2 \times 0.5 \times 0.5}{0.02^2} \approx 2401

异常处理监控

流水线再自动化,也得有人拍板。司哲定下“红灯制度”:异常包裹分三级——轻微异常(如地址格式不规范)放行但记录;严重异常(如外键缺失)直接进入“待检区”;致命异常(如主键为空)立即阻断整批数据,防止污染下游。大屏上跳动的红灯,就是数据管道的“血压计”。

对应到工程实现,检查失败后的策略分三类:阻断(Block,终止管道运行)、放行(Skip,记录异常继续)、纠正(Repair,用默认值或兜底逻辑修复后继续)。报警机制则在质量指标跌破阈值时触发:通过率低于 95% 发邮件,低于 90% 发短信,低于 80% 直接呼叫值班人。检查结果本身也应入库存档,形成质量趋势报表,供月度复盘与事故追溯。

质量监控常用混淆矩阵下的准确度衡量检查器自身水平:

司哲的大屏最终定格成一串趋势线:通过率、误报率、拦截量。他说,检查不是终点,让每个异常都有反馈、每个指标都有历史,才是数据质量的完整闭环。数港的数,从此越走越稳。

Accuracy=TP+TNTP+TN+FP+FN\text{Accuracy} = \displaystyle\frac{\text{TP} + \text{TN}}{\text{TP} + \text{TN} + \text{FP} + \text{FN}}
准确度 =(正确拦截的异常数 + 正确放行的正常数)÷ 全部判定数。它衡量“检查器自己有没有看走眼”。
  1. 真阳 TP异常数据被正确判定为异常,即真正被拦截的坏包裹。
    TP\text{TP}
  2. 真阴 TN正常数据被正确放行,即顺利过关的好包裹。
    TN\text{TN}
  3. 假阳/假阴 FP/FN误报与漏报,前者错杀好人,后者放走坏人。
    FP,FN\text{FP}, \text{FN}
  4. 整体准确度所有判定中判断正确的比例,衡量检查器自身的可靠性。
    TP+TNTP+TN+FP+FN\frac{\text{TP}+\text{TN}}{\text{TP}+\text{TN}+\text{FP}+\text{FN}}

AI 应用场景

机器学习训练管线的数据门禁

阶段:数据准备 / 特征工程

解决的问题:训练样本中含空值、重复 ID、超范围特征,模型会学到错误模式。传统方式是人工抽查,效率低且有滞后;AI 管道在数据进入特征工程前自动执行完整性检查,失败则阻断训练任务。

具体案例:某推荐系统团队在 nightly 特征构建任务中,对 user_id 做非空 + 唯一检查,对年龄字段做 0-120 范围校验,对 item_id 做引用完整性检查。某日用户表同步延迟,外键匹配率骤降到 88%,检查器自动告警并暂停训练,避免了一批脏特征污染模型。

实时风控数据流完整性监控

阶段:实时数据管道 / 流式处理

解决的问题:支付流水实时进入 Kafka,单条异常不会立刻体现但会累积成系统性风险。传统事后批处理无法及时拦截,实时完整性检查在流上逐条校验。

具体案例:风控系统对每笔交易流水执行非空(金额必须有值)、类型(金额为数值)、值域(0-100 万)、引用(商户 ID 需在商户表中存在)四重校验,失败消息进入死信队列并触发告警,风险团队可秒级响应处理。

数据仓库 ETL 后的质量审计

阶段:数据建模 / 质量监控

解决的问题:数仓 ETL 完成后无法确认数据是否完整,传统靠手工写 SQL 抽查,覆盖不全且耗时。自动化质量审计定期检查全表并输出报告,让“账对不对得上”成为可观测指标。

具体案例:数据团队每天 8:00 自动执行完整性校验作业,对比当日与昨日行数波动、外键匹配率、空值率,异常则阻断下游报表任务并通知数据 owner,财报季再未出现过数据对不上的事故。

Python 演示

python92 行
import refrom datetime import datetime  class IntegrityChecker:    """数据完整性检查器:模拟数据管道中逐行验货的检查员"""     def __init__(self, records):        self.records = records        self._errors = []        self._seen = set()     def check_not_null(self, fields):        for row in self.records:            for field in fields:                value = row.get(field)                if value is None or str(value).strip() == "":                    self._errors.append((row.get("id"), field, "非空校验失败"))        return self     def check_unique(self, field):        for row in self.records:            value = row.get(field)            if value in self._seen:                self._errors.append((row.get("id"), field, "唯一性校验失败"))            else:                self._seen.add(value)        return self     def check_type(self, rules):        for row in self.records:            for field, expected in rules.items():                value = row.get(field)                if expected == "int" and not isinstance(value, int):                    self._errors.append((row.get("id"), field, "类型校验失败"))                elif expected == "date":                    try:                        datetime.strptime(str(value), "%Y-%m-%d")                    except ValueError:                        self._errors.append((row.get("id"), field, "日期格式失败"))        return self     def check_range(self, rules):        for row in self.records:            for field, (low, high) in rules.items():                value = row.get(field)                if value is not None and not (low <= value <= high):                    self._errors.append((row.get("id"), field, "范围校验失败"))        return self     def check_regex(self, rules):        for row in self.records:            for field, pattern in rules.items():                value = str(row.get(field, ""))                if not re.fullmatch(pattern, value):                    self._errors.append((row.get("id"), field, "格式校验失败"))        return self     def report(self):        total = len(self.records)        bad = len(set(item[0] for item in self._errors))        return {            "total": total,            "bad_records": bad,            "good_records": total - bad,            "integrity_rate": round((total - bad) / total * 100, 2),            "sample_errors": self._errors[:5]        }  def main():    records = [        {"id": 1, "user_id": "A001", "age": 25, "score": 88.5, "date": "2025-01-15"},        {"id": 2, "user_id": "A002", "age": None, "score": -10.0, "date": "2025-02-01"},        {"id": 3, "user_id": "A001", "age": 31, "score": 100.0, "date": "2025/03/01"},        {"id": 4, "user_id": "A004", "age": 22, "score": 92.0, "date": "2025-01-20"},    ]    checker = IntegrityChecker(records)    result = (        checker        .check_not_null(["user_id", "age"])        .check_unique("user_id")        .check_type({"age": "int", "date": "date"})        .check_range({"score": (0.0, 100.0)})        .check_regex({"date": r"\d{4}-\d{2}-\d{2}"})        .report()    )    print("完整性检查报告:", result)  if __name__ == "__main__":    main()
目的:用 60 行实现一个多关卡的数据完整性检查器,展示非空、唯一、类型、范围、格式五类检查的链式组合。
  1. def check_not_null(self, fields):定义“塑封检查”关卡,遍历指定字段寻找空值。
  2. if value is None or str(value).strip() == "":空值和空白字符串都算缺失,避免“看起来有值其实是空格”的漏网之鱼。
  3. self._errors.append(...)把问题记录写入错误清单,格式为(记录 ID,字段名,失败原因)。
  4. def check_unique(self, field):用集合靠“记忆”判断单号是否重复,相当于扫码枪。
  5. if value in self._seen:出现过就是重复,否则加入集合等待后续比对。
  6. datetime.strptime(str(value), "%Y-%m-%d")尝试按指定格式解析日期,失败即抛出异常并记录。
  7. def check_range(self, rules):用上下界判断数值是否越限,对应尺子蔡的限重测量。
  8. def check_regex(self, rules):用正则表达式匹配格式,对应老会计的格式较真。
  9. "integrity_rate": round((total - bad) / total * 100, 2)计算并通过率保留两位小数,作为体检核心指标。
  10. .check_not_null([...]).check_unique("user_id")链式调用让多个检查关卡像流水线一样依次执行。

常见误区

误区“只要每个字段都不为空,数据就是完整的。我把 NOT NULL 加完就万事大吉了。”

正解完整性是“该有的都有 + 该对的都对”的组合。非空只是第一关:一个字段非空但值可能重复、格式错误、超出范围、引用不存在的记录。好比包裹不是空箱子,也可能贴错标签、放错货物,甚至包裹本身是调包的。

为何常见:非空最容易理解,入门时最先接触 NOT NULL,自然误以为这就是全貌。

误区“我在代码里已经写了 if 判断,数据不会出错,数据库加不加约束无所谓。”

正解应用层校验只覆盖当前程序写入的路径,批量导入、手动 SQL、其他团队脚本都能绕过它制造脏数据。管道入口或数据库层的统一校验才是最后防线。就像收货中心只信送货单不算数,还得仓库系统里的仓单对得上。

为何常见:开发者习惯了在自己代码里验证输入,低估了数据管道多头写入的现实。

误区“数据量太大,抽 1% 检查一下就行,反正结果差不多。”

正解抽样适合评估整体趋势,不擅长发现稀有问题——一个影响某条罕见业务路径的脏数据,在 1% 样本里可能根本碰不到。主键、外键等关键约束应全量检查,抽样只适合做分布类指标的辅助监控。

为何常见:全量扫描耗时耗资源,性能压力让人想走捷径。

误区“MD5 校验一致,这段 JSON 肯定没被改过。”

正解MD5 存在已知碰撞攻击,且校验范围有限。哈希一致只能说明“参与计算的内容一致”,覆盖不到未参与字段。生产环境应使用 SHA-256 并明确校验范围。好比开箱只点了瓶子数量,没看瓶里装的是酒还是水。

为何常见:人们容易把“校验工具”当成“全知管家”,忽略了它的适用边界。

误区“检查跑过了就行,报错信息看一眼删掉就好,反正没出大事。”

正解检查结果本身也是数据资产。通过率趋势、失败模式分布、报警记录,是排查管道故障和持续改进的依据。没有历史记录,出了事故只能大海捞针,也无法向业务方证明数据可信。

为何常见:重“拦截”轻“观测”,忽略了可观测性本身就是工程质量的一部分。

面试题

Q1. 数据完整性检查的核心目标是什么?

单选题 · easy

  • A.提高存储空间利用率
  • B.确保数据准确、一致、完整← 正确答案
  • C.加速模型训练速度
  • D.增加数据的冗余备份

答案:B。完整性检查的本质是“信任校验”,确保数据在使用前具备准确、一致、完整的基本质量。A/C 属于性能优化范畴,D 属于可靠性设计,都不是完整性本身的定义。

Q2. 下列哪项属于非空检查?

单选题 · easy

  • A.判断字段是否有 NULL 值← 正确答案
  • B.判断字段值是否重复
  • C.判断字段类型是否为 int
  • D.判断字段是否在合法范围

答案:A。非空检查专门针对 NULL 与空字符串,确保关键字段有值。B 是唯一性,C 是类型,D 是范围,它们都是完整性检查的不同维度,但只有 A 属于非空检查。

Q3. 要检测一列中是否有重复值,最合适的方法是?

单选题 · mid

  • A.COUNT(*) 与 COUNT(DISTINCT) 对比← 正确答案
  • B.SUM(col) 分组求总和对齐
  • C.AVG(col) 计算平均判异常
  • D.MAX 与 MIN 求极值判断

答案:A。COUNT(*) 得总行数,COUNT(DISTINCT col) 得去重后数量,两者相等说明无重复,不等则有重复。B/C/D 都是聚合统计,无法直接判断单列取值是否重复。

Q4. 引用完整性检查主要用于发现什么问题?

单选题 · mid

  • A.字段为空导致的分析缺失
  • B.外键对应主键不存在← 正确答案
  • C.数据格式不规范难解析
  • D.数值超出业务允许范围

答案:B。引用完整性要求子表外键能在父表主键中找到对应记录,找不到的就是“孤儿记录”。A 属于非空问题,C 属于格式问题,D 属于值域问题。

Q5. 校验和与哈希的主要用途是?

单选题 · mid

  • A.字段取值范围越界
  • B.数据在传输中被篡改← 正确答案
  • C.外键关联出现缺口
  • D.数据量超出预期规模

答案:B。校验和与哈希对数据内容计算“数字指纹”,对比前后指纹来判断传输过程是否被篡改或损坏。A/C/D 分别属于范围、引用、容量问题,不是哈希的职能。

Q6. 某字段要求 yyyy-MM-dd 格式,下列哪种检查最合适?

单选题 · hard

  • A.非空检查排除空值
  • B.范围检查限制区间
  • C.正则表达式格式校验← 正确答案
  • D.哈希校验防篡改

答案:C。日期格式属于格式约束,最适合用正则表达式做模式匹配,如 ^\d{4}-\d{2}-\d{2}$。A 只查空值,B 只查数值边界,D 防篡改,都无法验证格式是否合规。

Q7. 一张 1 亿行的表需要每天检查完整性,最合理的策略是?

单选题 · hard

  • A.每次全量扫描保证准确
  • B.分层抽样结合定期全量← 正确答案
  • C.不再检查节省算力
  • D.只检查前一千行即可

答案:B。每次全量扫描成本过高,完全不查或只看前 1000 行不可靠。合理策略是对主外键等关键字段全量检查,对分布类指标用统计抽样,并定期做一次全量复核,兼顾成本与风险。

Q8. 数据完整性检查通常包含哪些维度?

多选题 · mid

  • A.实体完整性(主键唯一)← 正确答案
  • B.引用完整性(外键关联)← 正确答案
  • C.域完整性(类型与范围)← 正确答案
  • D.索引设计与性能调优

答案:ABC。四大维度是实体完整性(主键非空唯一)、引用完整性(外键有效)、域完整性(类型与值域合法)以及用户定义完整性(业务规则)。D 是性能优化,不属于完整性维度。

Q9. 以下哪些做法会削弱数据完整性检查的效果?

多选题 · hard

  • A.只在应用层校验,数据库无约束← 正确答案
  • B.全量校验周期过长,增量未覆盖← 正确答案
  • C.校验失败后静默忽略不处理← 正确答案
  • D.用哈希校验检测字段水平

答案:ABC。应用层校验会被绕过产生漏网脏数据;全量周期过长导致增量数据长期未检;失败后静默忽略等于白查,这三者都会削弱检查效果。D 是正当的篡改检测手段,不会削弱效果。

Q10. 关于数据质量监控指标,下列说法正确的是?

多选题 · hard

  • A.完整性通过率 = 通过数 / 总记录数← 正确答案
  • B.只需关注通过率,无需关注失败模式
  • C.异常报警需要设置合理阈值← 正确答案
  • D.检查结果应记录并用于审计← 正确答案

答案:ACD。通过率是核心质量指标;报警阈值要合理,避免误报风暴或漏报;检查结果应留档用于趋势分析和事故追溯。B 的错误在于失败模式分析是定位根因的关键,只看通过率无法知道“哪里坏了、为什么坏”。