订阅更新

数仓多值维度和桥接表怎么设计?

面试问 072 约 3 分钟读完 1 次阅读

本文目录
  1. 面试怎么回答
  2. 先确认事实粒度能不能调整
  3. 桥接表如何表达多值关系?
  4. 最容易踩的坑:指标重复计算
  5. 关系会变化时怎么办?
  6. 一个常见错误设计

面试怎么回答

多值维度是指一条事实在既定粒度上同时关联多个维度成员。能自然拆分度量时,我会考虑细化事实粒度;不能拆分时,用组键和桥接表表达多对多关系。设计时重点明确事实粒度、关系有效期和统计口径:影响分析可保留完整度量但不能跨成员相加,需要可加汇总时必须维护权重且组内权重和为 1,避免 Join 后重复计算。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

一笔订单同时关联三个营销标签。如果直接把订单事实表和标签关系表 Join,订单金额会复制三份。

标签分析有了,GMV 却被放大了。这个问题该怎么建模?

这类场景的本质是:事实表一行在当前粒度上,对同一个维度同时存在多个合法取值,普通的一对多维度外键已经无法表达。


先确认事实粒度能不能调整

假设订单事实表粒度是“一行一笔订单”,一笔订单可以关联多个营销标签。

第一反应不应该是立刻建桥接表,而要先判断:业务度量能不能自然拆到“订单 + 标签”粒度。

如果每个标签都对应明确的金额分摊,事实表可以直接细化粒度,保存每个标签分得的金额。此时各行度量仍然可加,模型也更直接。

但如果标签只是描述订单影响因素,订单金额无法自然拆分,强行把事实表复制成多行就会造成重复统计。这时桥接表更合适。

桥接表如何表达多值关系?

常见设计是:

订单事实表
  └─ 标签组键
       └─ 标签桥接表:标签组键 + 标签键 + 权重
            └─ 标签维度表

同一组标签共享一个标签组键,桥接表为组内每个标签保存一行。事实表只保存一次订单金额,通过标签组键找到全部关联标签。

多值维度桥接表结构

桥接表至少要明确:

  • 关联的是哪一种事实粒度
  • 每组包含哪些维度成员
  • 同一成员是否允许重复
  • 是否需要主标签、排序或关系类型
  • 关系是否随时间变化

最容易踩的坑:指标重复计算

订单金额 100 元,关联 A、B 两个标签。Join 后两行都是 100 元,直接按标签汇总会得到 A=100、B=100。

如果目的是看“哪些标签影响过这 100 元订单”,这种结果可以作为影响口径,但不能再把 A 和 B 相加理解为总 GMV。

如果报表要求标签金额可加,就需要在桥接表中维护分摊权重,例如 A=0.6、B=0.4:

allocated_amount = order_amount * allocation_weight

并确保同一标签组的权重之和等于 1。

影响口径与分摊口径的区别

所以使用桥接表前,必须先告诉下游指标属于哪一种口径:

  • 影响口径:每个标签都看到完整事实值,不允许跨标签累加
  • 分摊口径:按权重拆分事实值,可以跨标签汇总
  • 去重口径:只统计事实主键去重后的数量,不直接求和明细度量

关系会变化时怎么办?

交易发生时就固定下来的标签组,可以把当时的组合固化在事实记录上。

如果是“账户—客户”“组织—成员”这类会随时间变化的多对多关系,桥接表还要考虑生效时间、失效时间以及两侧维度的历史版本。查询必须约束到同一业务时点,否则今天的关系可能被错误套到过去的事实。

一个常见错误设计

为了省事,在事实表里增加 tag_1、tag_2、tag_3 三个字段。

这种设计看起来不用桥接,但标签数量一变化就要改表;查询某个标签时要同时扫描多个字段,也很难表达排序、权重和生效时间。

桥接表的价值,就是用行扩展表达开放数量的多值关系。但它也会增加查询复杂度,所以要配套语义视图、权重规则和重复统计检查。


刷题进度保存在当前浏览器