数据质量管理(DQC)落地:SQL探针与dbt监控实战
2026/9/19 18:47:28 网站建设 项目流程

简介:数据质量管理(DQC)主题PPT,系统讲解数据质量管理的关键概念、评估维度、管理流程与落地方法,适合数据治理、数据平台开发及数据分析从业者学习参考。内容覆盖数据质量概述、评价方法、管理实施与数据质量愿景四大模块,具体包括完整性、一致性、准确性、真实性、唯一性、关联性、及时性等评估维度,以及事前定义、事中监控、事后分析的管理流程;并细化非空性、有效性等稽核场景,给出电话、邮件、短信等告警机制,便于在数据质量监控体系建设中直接借鉴。包体为单个pptx文件,约10.27MB,图文形式呈现,既可用于个人系统梳理,也可作为团队培训与方案汇报的讲解材料。已有723人学习,适合数据治理体系搭建、数据质量规则制定及日常质量监控实践等场景。

1. 数据质量管理(DQC)为什么总是一页漂亮的PPT

审计抽查发现订单表金额字段有8%是负数;BI看板里用户数一夜涨了40%,最后定位是上游宽表的去重逻辑被人改了;凌晨两点管道失败,数据组和数仓组在群里互相“甩锅”。这时候你翻出去年汇报用的那页《数据质量管理(DQC).pptx》,上面只有环形图、四象限和一句“提升数据可信度”。问题不在PPT画得不好,而是我们把DQC做成了汇报材料,没有做成一整套可执行、可验证、可度量的工程系统。

数据质量管理(DQC)真正要回答的是三个问题:质量规则怎么定义不靠拍脑袋、坏数据在数据管线哪一层能被拦住、以及拦下来之后如何证明它真的有效。本文就按这条线展开:先用SQL探针把质量维度落成具体指标,再讲如何在dbt和Great Expectations这类工具上接入DQC,最后用一个可回算的质量分卡来验收效果。适合正在做数据平台治理、管线监控以及为“质量项目”编预算的数据开发与架构师。

2. 动手定义DQC规则:六维质量度量与SQL探针

2.1 先把“质量”拆成能计算的质量维度

数据质量管理(DQC)落地时最忌讳一上来就搭大平台。我一般的做法是先和业务对齐“哪些数据不能用”,反推质量维度。业界常用的数据质量六维模型覆盖面够用:完整性、准确性、唯一性、一致性、及时性、有效性。每个维度落到表上,都应该对应一个可计算的探针。

维度典型问题常用探针计算方式
完整性核心字段为空count(*) - count(col)得到空值数
准确性金额为负、日期越界count(*) FILTER (WHERE col <= 0)得到非法值数
唯一性主键重复count(*) - count(distinct key)得到重复键数
一致性宽表与明细对不上join后计算两表同维度值的差集
及时性分区产出晚于业务时点检查max(etl_time)与当前时间的差值
有效性枚举值不在字典表中left join字典表,统计未匹配行数

新项目我不会把六维一次做全,而是先做完整性、准确性、唯一性这三个最容易被业务理解的维度。原因有两个:一是这三类规则的SQL写起来简单,业务方看一眼就能确认口径;二是它们能覆盖大多数“数据能不能用”的问题。一致性通常涉及两张表的对齐,等探针框架跑通之后再加也不迟。

2.2 用一次SQL探针返回五个关键指标

下面的探针针对订单明细表,一次查询同时输出行数、重复键、空值、负金额比例和非法状态比例。这段SQL在PostgreSQL语法下可以直接执行,其他方言改一下FILTER写法即可。

-- 探针:一次查询算出订单表的五类质量指标 WITH src AS ( SELECT order_id, customer_id, amount, status, etl_time FROM dwd.orders WHERE dt = '2025-01-06' -- 分区条件,保证探针按天执行 ) SELECT COUNT(*) AS total_rows, COUNT(order_id) - COUNT(DISTINCT order_id) AS duplicate_keys, COUNT(*) - COUNT(customer_id) AS null_customer, ROUND( 100.0 * COUNT(*) FILTER (WHERE amount <= 0) / COUNT(*), 4 ) AS negative_amount_ratio, ROUND( 100.0 * COUNT(*) FILTER ( WHERE status NOT IN ('OPEN', 'PAID', 'CANCEL') ) / COUNT(*), 4 ) AS bad_status_ratio FROM src;

这段探针不修改任何数据,它把一张表的状态压缩成五个数字。total_rows用于辅助判断行数波动;duplicate_keysnull_customer是整数型绝对指标;negative_amount_ratiobad_status_ratio用百分比表达。生产环境我会把这五个数字写入monitor.dqc_metric表,字段包括metric_datetable_namerule_codemetric_value,这样后续做趋势分析和告警阈值才有历史数据可查。

2.3 把探针沉淀成规则配置,而不是为每个问题写一套新SQL

探针多了以后,最怕的是规则散落在各种临时脚本里。我会把规则收敛成YAML配置,由一个统一的DQC Runner读取后动态生成SQL。配置里表达的是“要检查什么”,而不是“这个SQL怎么写”。

rules: - table: dwd.orders partition: dt probes: - code: order_dup dimension: uniqueness expression: "count(*) - count(distinct order_id)" threshold: 0 severity: P1 - code: order_amount_neg dimension: accuracy expression: "ratio(amount <= 0)" threshold: 0.005 severity: P2 - table: dwd.users probes: - code: user_null_mobile dimension: completeness expression: "null_ratio(mobile)" threshold: 0.01 severity: P2

Runner的解析逻辑并不复杂:读入YAML后,把ratio(amount <= 0)展开成上面写的FILTER写法,把null_ratio(mobile)展开成count(*)-count(mobile)count(*)的比值,再按tablepartition拼成探针SQL。这里有两个参数值得注意:threshold是触发告警的临界值,severity决定告警级别,P1表示阻断下游,P2表示仅通知。把阈值放进配置而不是代码里,业务方想调口径时就不用等开发改脚本。

2.4 阈值不要拍脑袋:先干跑两周再定基线

很多DQC项目死在阈值的设置上:定得太松,脏数据悄悄溜过去;定得太紧,告警满天飞,最后没人看。我一般不给客户直接拍阈值,而是先干跑两周,把每天的metric_value记录下来,再根据P95或P99分位设阈值。例如某表的负金额比例连续14天都低于0.1%,预警阈值就设在0.2%,再留出一天的抖动空间。

比例类指标在小表上会剧烈跳动,所以Runner里必须加一个min_row_count参数。当total_rows小于100时,跳过比例类探针,只保留完整性等绝对指标。还有一个常见做法是给阈值加“连续触发次数”,比如连续三次超过阈值才告警,避免重跑任务或临时数据修补造成的偶发抖动。这一步虽然简单,却能淘汰掉一大批无效告警。

3. 把DQC接进数据管道:dbt与Great Expectations的落地配置

3.1 先选型:自己的SQL探针离规则引擎还差什么

前面用YAML配探针,已经能解决“规则散落”的问题,但它本质上还是一套自研脚本。自研脚本的优点是贴合现有方言、改造快,缺点是结果展示、失败行留存、与调度系统集成都要自己写。当团队规模变大、数据资产变多之后,我会优先在dbt和Great Expectations里做DQC,而不是继续扩建自己的Runner。

方案规则维护方式适合阶段接入成本失败处理
自研SQL探针自己写配置和代码表少、口径快速变化自己实现
dbt tests与模型定义放一起管线已经用dbt失败行存入store_failures
Great Expectations独立Expectation Suite需要跨批、统计画像中高checkpoint多动作联动
Apache Griffin平台化管理大团队、统一治理自带告警与展现

一个简单的选型原则:管线已经在用dbt的项目,先用dbt的data test把行级和列级校验跑起来;如果没有统一的建模层,但需要一个独立的检查工具,就直接用Great Expectations;只有当团队要建设企业级数据资产目录和权限管控时,才值得考虑Apache Griffin这类重量级平台。下面的内容围绕“dbt + Great Expectations”展开,这是数据团队从零搭建DQC最顺手的一条路径。

3.2 用dbt的data test做列级与行级校验

dbt的测试定义在schema.yml里,它和模型代码放在同一个仓库,规则跟着模型走,这一点比单独维护一套规则库更符合数据开发的直觉。

# models/staging/schema.yml version: 2 models: - name: stg_orders columns: - name: order_id tests: - not_null - unique - name: status tests: - accepted_values: values: ['OPEN', 'PAID', 'CANCEL'] - name: amount tests: - not_null

内置测试只解决空值、唯一性、枚举值这类常规检查。更复杂的业务规则要自定义测试,本质就是写一条返回“问题行”的SQL,dbt会把返回的行判定为失败。

-- tests/assert_amount_not_negative.sql -- 目的:让金额字段为负的订单行直接暴露出来 SELECT order_id, amount FROM {{ ref('stg_orders') }} WHERE amount < 0

运行测试的命令如下:

dbt test --select stg_orders --store-failures

--select可以指定模型名,也可以指定tag;--store-failures会把失败的行写入dbt_test__audit表,方便后续生成“问题凭证”报告。自定义测试里{{ ref('stg_orders') }}会解析成实际的物理表名,所以测试SQL不需要写死schema,环境切换时也能跟着模型一起走。--threads参数可以控制并发,测试量大时可以适当调高,但要注意数据库连接数限制。

3.3 用Great Expectations补上跨列与统计画像

dbt tests擅长针对特定模型写规则,但如果要频繁做“金额应落在0到100万之间”“行数相对昨日波动不超过10%”这类统计画像,Great Expectations的Expectation表达更自然。它的标准做法是先定义Expectation Suite,再配置Checkpoint执行。

# gx_config.py from great_expectations.data_context import DataContext context = DataContext("/data/gx") suite = context.get_expectation_suite("orders_suite") suite.expectations.append( ExpectColumnValuesToBeBetween( column="amount", min_value=0, max_value=1000000 ) )

更常见的是把Checkpoint定义成YAML,执行和结果归档都走命令行动作列表。

# checkpoints/orders_checkpoint.yml name: orders_checkpoint module_name: great_expectations.checkpoint class_name: SimpleCheckpoint batch_request: datasource_name: dqc_source data_asset_name: dwd_orders expectation_suite_name: orders_suite action_list: - name: store_validation_result - name: notify_slack

执行命令:

great_expectations checkpoint run orders_checkpoint

这里的batch_request指定要校验的数据集,expectation_suite_name指定规则集,action_list是校验通过或失败后要执行的动作列表。我通常会在action_list里配置store_validation_result把每次校验结果归档,再通过notify_slacknotify_email接告警。这样即使某个批次失败,结果数据本身也是完整的,排错时有据可查。

3.4 在Airflow里接入DQC的推荐结构

Airflow接入DQC时,最容易犯的错误是把质量检查任务挂到主数据链路中间,失败就阻断整个DAG。这样做看起来严格,实际会让管线非常脆。我更推荐把DQC任务设计成“旁路”任务:主链路照常跑,DQC并行执行并把结果写入监控库,只有P1级别规则明确失败时才暂停后续任务。

# airflow_dqc_example.py from airflow import DAG from airflow.operators.bash import BashOperator from airflow.operators.python import PythonOperator dqc_orders = BashOperator( task_id="dqc_orders", bash_command="cd /data/gx && great_expectations checkpoint run orders_checkpoint", retries=1, retry_delay=timedelta(minutes=5), ) # DQC任务作为旁路并行执行,不阻塞主业务链路 load_orders >> [serve_business, dqc_orders]

retriesretry_delay控制失败时的重跑策略,重跑次数不宜过多,否则告警会被重试刷屏。如果确实需要阻断下游,可以在DAG里再加一个判断任务,读取DQC结果表,P1失败就调用下游DAG的clear或直接标记失败。判断逻辑和数据质量查询分开写,代码会更清晰。

4. DQC监控与告警:调度窗口、通知收敛和三个高频坑

4.1 给DQC设定合理调度时间:跟随数据可用性而不是机械定时

DQC任务跑得太早会误报“数据缺失”,跑得太晚会延迟告警。常见做法是把DQC调度时间设为“业务数据约定产出时间 + 等待窗口”。比如每天8点是业务系统数据的基线产出时间,DQC就定在8:30开始跑,并加一个前置判断,确认分区数据已经就绪。

-- 判断某个分区是否已产出,作为DQC任务的前置条件 SELECT 1 FROM dwd.orders WHERE dt = '{{ ds }}' HAVING MAX(etl_time) >= '{{ ts }}'::timestamp - INTERVAL '2 hours'

这里的{{ ds }}是Airflow的日期变量,INTERVAL '2 hours'是容忍的数据延迟窗口。若这个查询返回空,说明分区还没写完,DQC任务应该等待或跳过。把“数据可用性”和“质量检查”分开,能让告警更准确:前者对应及时性维度,后者才对应完整性、准确性等维度,两者混在一起时排错非常痛苦。

4.2 把告警收敛到“人不会忽略”的粒度

数据质量告警最怕的不是没有,而是太多。团队里每多一条没人看的告警,真正重要的告警就少一分注意力。我给告警分了四级,让不同级别走不同通知渠道。

级别场景动作
P0主键表全量丢失、核心报表无法产出电话或值班群,立即处理
P1重复键超过阈值、核心空值率超限工作群通知,阻断相关下游
P2比例型指标超限但影响可控仅记录,日汇总
P3轻微波动、疑似口径变化写库,关注趋势

通知内容我会用Webhook直接推送到团队群,并带上表名、规则、阈值、实测值和issue标识。

curl -X POST "$DQC_WEBHOOK" \ -H "Content-Type: application/json" \ -d '{ "msgtype": "markdown", "markdown": { "content": "DQC告警 [P1] dwd.orders 完整率实测97.8%,阈值99%,issue=order_dup" } }'

Webhook地址不要写死在代码里,放环境变量或密钥管理服务,避免误发到测试群。这里的核心是issue标识位,后续告警去重、合并时,按table_name + rule_code + partition_date生成同一标识,相同标识两小时内只通知一次,连续多次则升级级别。

4.3 三个让DQC失效的高频坑

第一个坑是只看比例不看行数变化。空值率从1%降到0.5%,听起来质量变好了,但行数同时掉了一半,意味着上游数据源被截断。应对办法是在每个探针里都带上total_rows,并单独配置一行数波动规则,比如环比昨日超过20%就告警,足够拦截大多数异常。

第二个坑是不分区跑探针。只有几百行的测试表可以全表检查,到了亿级宽表,全表扫描既慢又让阈值失去意义。正确做法是按分区执行探针,然后把同一分区不同时间的指标用来做趋势对比;对超大表则用TABLESAMPLE或对关键键值做分层抽样。参数上给探针加partition_columnsample_rate,比改SQL来得灵活。

第三个坑是DQC失败直接打断生产链路。前面已经把DQC设计成旁路,但有时业务方坚持要让坏数据“根本到不了下游”。这时不要在DAG里粗暴地raise,而是把阻断逻辑交给人审阅:DQC失败先发通知,值班人确认后再暂停下游任务。机器负责发现问题,人负责决策,这种模式在跨团队配合时摩擦最小。我见过太多严格阻断的案例,最终都因为误报太多被业务方要求绕过检查,反而失去了DQC的意义。

5. 用数据质量分卡验证DQC:一个可复算的评分模型

5.1 给每个探针一个0到100的得分

告警只能说明“有没有出问题”,质量分才能说明“整体趋势是变好还是变坏”。我给每个探针设计一个得分映射,再做加权汇总。完整性、准确性、唯一性三个维度先行落地时,权重按30%、30%、15%分配,预留25%给及时性和一致性。

SELECT metric_date, table_name, rule_code, CASE WHEN dimension = 'completeness' THEN CASE WHEN completeness_pct >= 99.0 THEN 100 WHEN completeness_pct >= 95.0 THEN 80 ELSE 0 END WHEN dimension = 'uniqueness' THEN CASE WHEN duplicate_cnt = 0 THEN 100 WHEN duplicate_cnt <= 5 THEN 80 ELSE 0 END ELSE 60 END AS score FROM monitor.dqc_metrics;

得分汇总时,先按维度分组求均值,再乘以权重求和。这张表可以按周汇总,形成一条趋势线,比零散的告警记录更能说明DQC是否在起作用。分数本身不需要特别精确,关键是可复算:任何人拿着同样的指标表都能算出同一个分。

5.2 用“历史问题回放”验证DQC有没有拦住该拦的

验证DQC效果最有效的方法,不是看告警减少了多少,而是回放历史故障。具体做法:从运维事故单和客服反馈里找出最近一个季度的20个数据问题,每一条映射到对应的质量规则,再用规则去当日分区里重新执行,看能否复现问题。

问题描述对应规则回放结果
订单金额为负导致财务对账异常amount >= 0命中
用户手机号重复注册mobile 唯一性未命中,规则缺失
宽表与明细行数不一致行数波动探针命中

回放得到的“覆盖率”比告警量有价值得多,如果只有60%的问题能被已有规则命中,说明DQC的规则库还远没有闭环。我会把每次回放发现的漏网问题直接补成新规则,并把首次回放时的命中率作为基线,之后每个季度回放同一批问题,看覆盖率有没有提升。这样DQC的迭代就有可对比的起点,而不只是“做了个平台、挂了块看板”。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询