数据质量:四条校验、三方对账与异常清单

一次「激活率提升 9%」的复盘,被两天的 SDK 故障推翻。本文给出量级、必填属性、event_id 唯一与时间偏差四条每日校验,一张分析库、应用日志与支付回调的三方对账表,以及把差异拆成可解释条目、能直接照着查的异常清单。

数据坏了不会报警,它只会安静地给你一个更好看的数字。

一、那个 9%,是 SDK 送的

陈默一个月后回看仪表盘,发现激活率从 53.9% 升到 59.3%。他准备把这条写进月度复盘,草稿标题都想好了:新手引导改版奏效,激活率提升 9%。写之前他顺手点开分日曲线,发现提升只出现在两个尖峰上,其余二十八天纹丝不动。

他去查那两个尖峰对应的日期,正好是发版后的两天。再查事件明细,source 属性在那两天是空字符串——SDK 版本发错了,分析口径要求 source 非空才计入注册,于是 104 条注册被静默排除在分母之外。分子没变,分母小了,比率自然好看。

更麻烦的是,付费转化率也跟着涨了。同一个故障同时推高了两个指标,复盘里看起来就像一次全面的改版成功;如果他没有点开分日曲线,这条结论会一路写进下季度的路线图。

以下情境为教学假设,人物、引语和数字不代表经核实的真实案例。

数据坏了不会报警,只会安静地给出错误结论。 服务挂了有监控,接口慢了有告警;事件属性缺失没有任何东西会变红,报表照常刷新,只是数字错了。

校验要能自动跑。 靠人每月翻一遍曲线,翻到问题全凭运气;写成查询、挂在每天固定时间,才有机会在写进复盘之前拦住。

三方对账是最后一道。 分析库自己跟自己比,永远自洽;拿应用日志和支付回调对一遍,才能发现「少记了」和「多记了」。

异常清单比阈值更重要。 阈值只告诉你「超了」,清单告诉你去查什么;没有清单的告警,最后都会被人静音。

二、四条校验

四条就够,每条都能写成一句查询。判据不要追求精确,追求「异常时一定会响」。

校验判据频率触发后动作
量级当日事件数较前 7 日均值偏离 ±30%每日冻结当天看板,查发版与采集开关
必填属性缺失率任一必填属性为空的比例 < 1%每日按属性与版本分组,定位到具体 SDK 版本
event_id 唯一重复 event_id 占比 < 0.5%每日查重试与补发逻辑,确认是否重复计数
服务端与客户端时间差偏差超过 5 分钟的占比 < 1%每周查设备时钟、时区与离线补传

量级校验抓的是「断了」,不是「错了」。 采集停摆、发版漏埋、开关误关,都会让当日量级掉一半;±30% 是最粗也最有效的一层。

必填属性要事先定义。 24 个事件乘 6 个属性共 144 个字段,不可能全是必填;只把影响分母的字段列进去,本文的场景里是 source、plan、user_id 三个。

event_id 重复通常来自重试。 客户端断网重发、服务端超时补发,都会产生重复;0.5% 以内可以接受,超过就说明重试没有幂等。

时间差校验决定「按天」还可信不可信。 偏差超过 5 分钟的事件会被归到相邻日期,月初与月末的对比就会失真。

四条校验的查询要放在同一个面板上。 分开看会漏掉联动:量级掉了、缺失率同时升了,基本可以确定是同一次发版。

三、三方对账

单看分析库,12,960 条事件没有任何问题;把它和另外两个来源放在一起,差异才浮出来。

来源月计数与主库差异差异解释
分析库(主库)12,960—按事件字典入库,去重后的口径
应用日志13,375+415(+3.2%)312 条重试重复,加 103 条缺 user_id 的匿名事件被丢弃
支付回调120 笔订阅事件−2 笔(跨月)回调在次月 1 日 00:03 到达,计入下月

两个计数天然不等价。 应用日志记的是「请求」,分析库记的是「有效事件」;前者包含重试与匿名流量,后者按字典过滤。指望它们相等,只会得到一张永远对不上的表。

对账的目的不是相等,是差异可解释。 415 条差异必须能拆成 312 加 103;拆不出来,就说明还有一类没被命名的丢失。

支付回调是最硬的外部锚点。 120 笔订阅是钱,分析库里的 subscription_started 是数;两者差 2 笔可以解释,差 20 笔就是采集链路出了问题。

差异要写进当月记录。 下个月再对时,你会忘了这 415 条是什么;一行解释能省掉半小时复查。

对账频率按月就够。 校验是每日的,对账是每月的;前者防突发,后者防慢性漂移。

四、复算:13 小时换回 48 小时

把四条校验与三方对账放进一个月的数字里,投入产出是可以算出来的。

月事件 = 12,960
必填缺失 = 12,960 × 0.8% = 104 条
重复 event_id = 12,960 × 0.3% = 39 条
应用日志 − 分析库 = 13,375 − 12,960 = 415 条(415 ÷ 12,960 = 3.2%)
时间戳偏差 = 12,960 × 0.6% = 78 条
每周核对 15 分钟 × 52 周 = 780 分钟 = 13 小时/年
错误结论成本 = 每月 1 次 × 4 小时 = 48 小时/年
净收益 = 48 − 13 = 35 小时/年

104 条缺失就是那次提升的全部来源。 分母从 1,150 掉到 1,046,620 ÷ 1,046 = 59.3%,对比 620 ÷ 1,150 = 53.9%,相对提升约 10%;草稿里写的 9% 反而还是保守的。数字没有撒谎,是分母被挖走了一块。

415 条差异拆得开,才敢签收。 312 条重试重复说明客户端重发没有幂等键,103 条匿名事件说明注册前的行为没有 user_id;前者要修,后者要决定是否保留。

39 条重复会直接抬高转化。 如果同一次激活被记两遍,分子变大、分母不变,转化率就虚高;重复率 0.3% 看似很小,落在 620 的激活分子上就是 2 条。

78 条时间戳偏差影响的是趋势,不是总量。 它们会把月初的事件挪到上月月末,单看月总量没事,看日曲线就会在边界处出现假的尖峰。

13 小时不是成本,是保费。 它买的是「错误结论在写进复盘之前被拦下」;按每月一次、每次 4 小时估算,一年拦下一次就回本。

异常出现时,按清单查,不要从零想。 下面这张三列表就是清单本体,贴在告警消息里,比一句「数据异常」有用得多。

现象最可能原因先查什么
当日总量掉三成采集开关、发版漏埋发版记录与 SDK 版本分布
某属性缺失率突升字段改名、默认值丢失该属性按版本分组的空值率
注册数涨但激活不涨重复计数、匿名流量混入event_id 重复率与 user_id 空值率
月末出现尖峰离线补传、时区偏移时间戳偏差分布与补传批次

五、行动清单与复算验收

先做能自动跑的,再做好看的。以下八条按顺序执行。

  • 从 24 个事件里挑出影响分母的三个必填属性。
  • 把四条校验写成查询,固定每天 09:00 运行。
  • 给每条校验配一条「触发后动作」,写清先查什么。
  • 导出上月应用日志条数,与分析库做第一次对账。
  • 把差异拆成「重复」「丢弃」「跨月」三类并写明条数。
  • 用支付回调核对订阅事件,记录可关联比例。
  • 把异常清单三列贴进告警消息,替换「数据异常」四个字。
  • 每月记录校验拦下的错误结论条数与节省时间。

验收标准:任何一个月的关键数字,你都能说清它是怎么来的、差在哪、差的那部分去了哪里;说不清,就还没有对账。

使用边界与实操验收

本文不替代数据仓库的完整性约束。 主键、外键、非空约束该建还是要建;四条校验是约束之外的运行时兜底,两者不冲突。

校验阈值要按自己的量级调。 ±30% 与 1% 是本文基线下(月 12,960 条)的经验值;日事件只有几十条时,任何比例都会被单条事件放大。

对账需要第二个来源。 只有分析库一个来源时,只能做内部一致性检查;应用日志与支付回调是最容易拿到的两个外部锚点。

不要为了对账保留全量日志。 日志按需保留三十天即可,长期留存看的是聚合后的计数;保留策略属于成本问题,下一篇 再展开。

验收看的是「拦下过什么」。 连续三个月一条异常都没拦到,要么数据真的干净,要么阈值宽到失效;两种都要复查。

关键参考与核验范围

核验日期:2026-10-26。以下链接用于核对数据测试、字段校验与日志数据模型的一般做法,本文未逐条引用其内容。

引用口径。 本文只借用「把校验写成可自动运行的测试」这一一般做法;四条校验的阈值、12,960 条事件与 48 小时全部是教学假设,与上述材料无关。

核验范围。 核验的是四条校验与三方对账这套结构是否仍可操作,不是比对某个分析工具的校验功能清单。

如何自行复核。 拿上个月的数据跑一遍四条校验,再把应用日志条数抄下来与分析库相减;如果差异拆不出三类,说明你的异常清单还缺一行。

系列导航

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「Indie」更多文章

  1. 开源项目验收:十项能力、四维评分与三种不该开源的项目
  2. 治理、fork 与退出:17 位贡献者、82% 的提交与一次改协议的代价
  3. 双许可与企业版:九家询价、两家成交与 4,800 美元