Skip to content

指标口径一致性 ​

难度与前置

难度:进阶
前置:知道分层职责;能写 GROUP BY / JOIN;接触过「看板 A 和看板 B 数对不上」。
读完能做什么:给核心指标建口径字典与唯一计算源,用层间/跨报表对账 SQL 把差异钉到具体原因。

适用场景 ​

  • 同一指标名(如「消耗」「GMV」「UV」)在多张报表、API、临时取数里数值对不齐
  • 业务方投诉「昨天日报和财务对账差 3%」
  • 新看板直接扫 ODS/DWD 自算,绕过主题汇总

不适用:

  • 尚未定业务过程与粒度(先做 分层)
  • 纯展示层字段别名不一致、实际计算同源(改命名即可)
  • 实时秒级波动 vs 离线 T+1 的预期差异未写清 SLA(先定义可接受误差)

真实场景(一条) ​

投放运营日报、渠道对账表、财务月报都叫「消耗」,但:

出口实际口径分区日
运营日报 ADS含税本币 + 含赠款账户时区日切
渠道对账 ADS不含税本币 + 不含赠款渠道账单日
财务月报含税本币 + 不含赠款入账会计日

三人各写 SQL,月中对不齐 4%~7%。根因不是「引擎算错」,而是同名异义 + 多处重算。

治理后:cost_amount 只在 DWD 定义一次;DWS 只 SUM;三张 ADS 用字典字段显式命名(cost_ex_tax / cost_incl_tax / cost_with_bonus),日对账 diff < 0.1%(舍入除外)。

怎么做(步骤清单) ​

1. 先列「同名指标」清单,再拆口径维度 ​

对每个争议指标,强制拆成可勾选维度(缺一项就不许叫同一名字):

维度可选值示例
业务过程计费入账 / 曝光计费 / 退款冲减后
金额含税含税 / 不含税
赠款/优惠含 / 不含
币种与汇率日本币;汇率取账单日 / 入账日
时间字段事件时间 / 入账时间 / 会计日
过滤is_valid=true;是否含测试账户
去重键bill_id / order_id+sku

输出物:一张 指标字典表(或配置中心),每行一个「指标编码」,禁止再用模糊中文名当唯一标识。

sql
-- 指标字典示意(可落 Hive 或配置库)
CREATE TABLE IF NOT EXISTS dim_metric_dict (
  metric_code      STRING COMMENT '如 cost_ex_tax_cny',
  metric_name_cn   STRING COMMENT '展示名:消耗(不含税本币)',
  business_process STRING,
  grain            STRING COMMENT '一行含义 / 汇总键',
  formula          STRING COMMENT '口径公式或引用表字段',
  time_field       STRING,
  filter_expr      STRING,
  owner            STRING,
  version          STRING,
  status           STRING COMMENT 'online/deprecated'
)
COMMENT '指标口径字典';

2. 唯一计算源:核心口径只算一次 ​

原则:

  1. 原子指标在 DWD(或指标中台)定义字段,注释写死口径
  2. 派生汇总只在 DWS SUM/COUNT(DISTINCT),禁止改公式
  3. ADS / 报表 / BI 只选字段、做展示过滤,禁止重写 cost = price * qty * tax_rate
sql
-- DWD:唯一权威字段
-- cost_amount = 不含税本币,不含赠款;含税另开 cost_amount_incl_tax
ALTER TABLE dwd_ad_spend_detail_di CHANGE COLUMN cost_amount cost_amount
  DECIMAL(18,4) COMMENT '权威口径:不含税本币,不含赠款;metric_code=cost_ex_tax_cny';

3. 报表出口强制引用 metric_code ​

看板、导出任务配置里写 metric_code,而不是自由 SQL 字符串。审查时 grep:

bash
# 禁止 ADS SQL 里出现「自创消耗公式」关键字(团队约定)
rg -n "cost_amount\s*\*|price\s*\*\s*qty|含税|赠款" ads_sql/ || true

4. 建「跨报表对账」日任务 ​

对同一 biz_date,抽核心指标做三角对账:

text
DWD 原子汇总  →  DWS 主题汇总  →  ADS_A / ADS_B

任意一边 diff 超阈值 → 阻断发布或告警认领(见 对账设计)。

sql
-- 日对账:DWD vs 运营日报 vs 对账表(同口径字段)
WITH dwd AS (
  SELECT dt, SUM(cost_amount) AS v
  FROM dwd_ad_spend_detail_di
  WHERE dt = '${biz_date}' AND is_valid = true
  GROUP BY dt
),
dws AS (
  SELECT dt, SUM(cost_amount) AS v
  FROM dws_ad_channel_play_1d
  WHERE dt = '${biz_date}'
  GROUP BY dt
),
ads_ops AS (
  SELECT dt, SUM(cost_ex_tax) AS v
  FROM ads_ad_daily_report_1d
  WHERE dt = '${biz_date}'
  GROUP BY dt
),
ads_recon AS (
  SELECT dt, SUM(cost_ex_tax) AS v
  FROM ads_ad_recon_channel_1d
  WHERE dt = '${biz_date}'
  GROUP BY dt
)
SELECT
  dwd.dt,
  dwd.v AS dwd_v,
  dws.v AS dws_v,
  ads_ops.v AS ops_v,
  ads_recon.v AS recon_v,
  dwd.v - dws.v AS diff_dwd_dws,
  dws.v - ads_ops.v AS diff_dws_ops,
  dws.v - ads_recon.v AS diff_dws_recon
FROM dwd
JOIN dws ON dwd.dt = dws.dt
JOIN ads_ops ON dwd.dt = ads_ops.dt
JOIN ads_recon ON dwd.dt = ads_recon.dt;

5. 差异归因树(按顺序排查) ​

  1. 口径维度是否一致(含税/赠款/过滤)——看字典
  2. 时间/分区日是否一致(账户日 vs 账单日)
  3. 粒度 Join 是否膨胀(见 Hive 数据倾斜 / Spark Join 倾斜)
  4. 是否漏分区 / 重跑未级联
  5. DISTINCT / 去重键不同
  6. 汇率、币种、精度 ROUND 位置不同

把每次事故记到 metric_incident(日期、diff%、根因编码、修复 PR),避免重复踩坑。

6. 变更治理:口径变更走版本 ​

  • 改公式 = 新 metric_code 或升 version,旧码 deprecated
  • 禁止原地改含义却沿用旧展示名
  • 回刷窗口与受影响 ADS 清单写进变更单

常见坑(至少牢记这些) ​

  1. 同名不同义
    都叫「消耗」,一个含税一个不含。字典没有 metric_code 时,对账永远是口水仗。

  2. ADS 各自重算
    「赶工期直接从 ODS 写报表」→ 三套清洗。短期快,一个月后无法统一补数。

  3. COUNT(DISTINCT) 与 SUM 混谈
    UV、订单数去重键不一致(设备 vs 用户 vs cookie),数值差一个数量级仍被当成「口径问题」乱改金额字段。

  4. 分区日与业务日混用
    事件落在 dt=T 分区,报表按入账日 account_dt=T 聚合,两边都「没错」但对不齐。

  5. 精度与 ROUND 时机
    明细 ROUND 到分再 SUM,与 SUM 后再 ROUND,月报可差几千。字典写明 ROUND 位置。

  6. 实时与离线未声明误差带
    实时少 1% 可能是 Watermark/迟到,不是口径 bug。先写 SLA 与对账窗口,再告警。

如何验收(可量化) ​

  • [ ] 核心指标均有 metric_code、公式、过滤、时间字段、owner、版本
  • [ ] DWD 注释可追溯到字典;DWS/ADS 无第二套核心公式
  • [ ] 日任务:DWD↔DWS↔至少两张 ADS 同码对账,|diff|/基准 < 约定阈值(如 0.1%)
  • [ ] 口径变更有版本记录与回刷范围
  • [ ] 抽一次历史事故:能用归因树在 30 分钟内定位到维度或 Join
sql
-- 验收:同码指标跨出口最大相对误差
SELECT
  metric_code,
  MAX(ABS(v1 - v2) / NULLIF(GREATEST(ABS(v1), ABS(v2)), 0)) AS max_rel_diff
FROM metric_recon_1d
WHERE dt = '${biz_date}'
GROUP BY metric_code
HAVING max_rel_diff > 0.001;
bash
# 字典与 ADS 引用完整性(示意)
wc -l conf/metric_dict.csv
rg -l "metric_code" ads_sql/ | wc -l

相关面试题 ​

占位:与题库小程序对齐后补链接(建议关联:指标口径一致性、同名指标对账、数仓分层与指标下沉)。


改写说明:结构与判断标准参考 Wood 原创数仓/面试文,已改写成可执行清单;未包含未公开公司数据与内部表名。