想象你是电商仓库的台账管理员。传送带日夜不停,成千上万的包裹从你面前滑过,每个包裹外皮上都贴着一串运单号。这串数字独一无二,能精准定位任何一个包裹;可你盯着它,却完全看不出里面装了什么、要寄给谁、有多重。想知道细节,你得拿起扫码枪去物流系统里查。 仓库另一角是客户资料柜,里面每个客户都有一张完整档案卡:姓名、电话、地址、会员等级,写得满满当当。于是你养成习惯——凡是值得记录的“对象”就开一个档案柜。可轮到包裹时你犯了难:每个包裹除了一串运单号外,什么信息都没有。为它单独开个档案柜?柜子里每个格子只放一张写着号码的纸条,柜子占地方,翻起来也费劲。 聪明的做法,是把运单号直接写进取货登记台账——也就是数据仓库里说的“事实表”——而不是为它建档案柜。这种“只有标识、没有属性”的特殊维度,在维度建模中被称为退化维度。本文就带你搞懂什么是退化维度、怎么识别它、如何设计,以及它与缓慢变化维的区别,让你在建模时不再为运单号犯难。

岗位关联

学会识别退化维度,你就能避免为无属性字段白白建几十万行的维度表,让事实表更精简、查询更快——这是维度建模实战中最容易立竿见影的基本功。

目录
  1. 可视化演示
  2. 认识退化维度
  3. 识别退化维度
  4. 设计原则
  5. 应用场景
  6. 对比缓慢变化维
  7. 建模实践
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态演示维度退化设计原理与应用的核心机制,通过基础/核心/应用/扩展四种模式展示关键概念与交互流程。

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

维度退化设计原理与应用:一维度退 一、维度退化概念与设计动机 二、退化维度的识别与特征 核心机制可视化 维度退化设计原理与应用整体架构与关键组件

认识退化维度

回到仓库的场景。客户的档案卡上可以写满信息,但运单号这张“纸条”上只有号码。如果哪个粗心的管理员非要给运单号也开一个档案柜,他很快就会后悔:柜子里成千上万张纸条,每一张都只写着一串数字,除了占地方没有任何收藏价值。在数据仓库的世界里,这串数字就是退化维度的化身。

数据仓库做维度建模时,事实表负责记录“发生了什么”——比如一张订单、一次支付;维度表负责描述“谁、什么、在哪”——比如客户、商品、门店。大多数业务对象都有丰富的属性,所以值得单独建维度表。但有一类字段比较特殊:订单号、发票号、运单号。它们能标识一个业务事件,但自身没有任何描述属性,单独建表只会得到一张“只有主键的空表”。

这种特殊的维度在维度建模中被称为退化维度(Degenerate Dimension),由 Ralph Kimball 最早提出。它的本质特征可以概括为三点:一是只有标识作用,二是不携带任何描述属性,三是取值基数极高——字段值几乎与事实表行数一一对应。正因为“无属性可存”,它不再单独建维度表,而是直接以普通字段的形式内嵌在事实表中,成为事实表的一个“残余标识”。

所以你看,运单号不是没有价值——恰恰相反,它非常重要,只是它的价值全在“标识”上,不在“描述”上。给它开档案柜是浪费,把它直接抄在登记台账上才是最顺手的做法。退化维度的思想,就是识破那些“只有号码的纸条”,不浪费一个柜子,也不丢失一个标识。

Degenerate  ⟺  Attr(D)=∅\text{Degenerate} \iff \text{Attr}(D) = \varnothing
一个候选维度 D 是否退化,就看它的属性集合是否为空集。空集说明它没有可描述的属性,只能退化为事实表里的一个标识字段。
  1. D 表示候选维度代表我们正在评估是否单独建表的业务对象,例如订单号、发票号、运单号。
    DD
  2. Attr(D) 表示属性集合所有能描述这个维度特征的信息,比如客户维度的姓名、电话、会员等级。
    Attr(D)\text{Attr}(D)
  3. 空集判定属性集合为空,表示这个维度没有值得归档的描述信息,只能作为纯标识存在。
    ∅\varnothing

识别退化维度

既然想通了“不为空档案开柜子”,新问题来了:怎么判断一份数据是“空档案”还是“有内容的档案”?方法很简单,看看这个字段有没有“私人物品”——也就是有没有属于自己的描述属性。运单号旁边跟着的重量、目的地,那是包裹的属性,不是运单号的属性;运单号自己能提供的,永远只有那一串数字。

识别退化维度可以走三步。第一步,属性检查:把所有可能描述这个维度的字段列出来,如果列完发现一个都凑不齐,它就是退化维度。第二步,基数判断:看这个字段的取值个数,订单号的取值几乎与事实表行数一样多,说明它根本没有“多行归并”的价值。第三步,用途观察:如果一个字段在分析中只用于定位单笔记录、关联外部系统、去重核对,而不是用于分组统计或描述业务,那就该考虑退化处理。

在建模评审会上,这三个步骤可以凝练成一个决策。把候选维度 D 的属性个数算出来,大于等于 1 就走建维度表的路线,等于 0 就直接退化为事实表字段。有人会问:“订单号旁边不是有下单时间吗?”注意,下单时间是事实表的度量或独立维度,它不是订单号“自己”的属性。判断时务必只数那些“离开这个标识就无法存在”的属性。

现在,仓库管理员再看到一张纸条时,只需要扫一眼:上面除了号码还有没有别的信息?没有,就大大方方写进台账。有了这个直觉,你就能在建模评审会上快速拍板——这个字段是“运单号型”还是“客户型”,一目了然。

decide(D)={dim table,∣Attr(D)∣≥1degenerate,∣Attr(D)∣=0\text{decide}(D) = \begin{cases} \text{dim table}, & |\text{Attr}(D)| \ge 1 \\[2mm] \text{degenerate}, & |\text{Attr}(D)| = 0 \end{cases}
决策规则:属性数量大于等于 1 就建维度表,等于 0 就退化为事实表字段。这是识别退化维度最硬性的分界线。
  1. 属性数量计算统计维度 D 拥有的描述属性个数,这是整个决策的输入。
    ∣Attr(D)∣|\text{Attr}(D)|
  2. 有属性建维表属性数大于等于 1,说明维度有内容可归档,值得单独建表管理。
    ≥1⇒dim table\ge 1 \Rightarrow \text{dim table}
  3. 无属性退化属性数等于 0,说明维度是空档案,直接作为字段落入事实表。
    =0⇒degenerate= 0 \Rightarrow \text{degenerate}

设计原则

“不为空档案开柜子”这句话,翻译成设计原则就是:不强建维度表。很多刚入行的建模师有“建表强迫症”,觉得凡是业务里出现过的对象,都得有张维度表才叫规范。可对退化维度来说,强行建表不仅浪费存储,还让 ETL 多一次插入、多一次关联,纯粹是给自己找麻烦。

第二条原则,原值直接入事实表。普通的维度在事实表里存的是代理键,比如用 customer_sk 代替冗长的客户编号;但退化维度恰恰相反,它要保留业务原值。因为订单号本身就是要被业务方和外部系统拿来对账的,换成代理键反而丢失了可读性。你想,台账上不写运单号,改画一个仓库内部编号,快递员还能认出哪个包裹是谁的吗?

第三条原则,保持字段单值且命名规范。一个事实行只对应一个订单号,不要在字段里塞逗号分隔的多个号码;字段名直接用 order_id、invoice_no 这样的业务术语,别用晦涩的缩写。还有一条底层判断:如果某个候选维度建表后,表行数与事实表行数几乎相等,那这个维度表连“去重”的价值都没有,建表的连接代价反而成了负担。

台账管理员把这四条原则贴在墙上:不建空柜子、原字照抄、一格一号、名字写清楚。这套原则看似简单,却能让事实表在保持信息完整的同时,轻装上阵,跑出更快的查询。

Ndim≈Nfact  ⇒  join 代价高  ⇒  宜退化N_{\text{dim}} \approx N_{\text{fact}} \;\Rightarrow\; \text{join 代价高} \;\Rightarrow\; \text{宜退化}
当维度表行数近似等于事实表行数时,连接该维度表只会徒增开销,此时应将其退化为事实表字段。
  1. 维度表行数候选维度表的预计行数,订单号这种字段几乎每行都不同。
    NdimN_{\text{dim}}
  2. 事实表行数事实表记录业务事件的总行数,是维度表行数的参照系。
    NfactN_{\text{fact}}
  3. 约等号的意义两者近似相等说明维度没有压缩信息的空间,退化成字段最经济。
    ≈\approx

应用场景

生活中“只有号码的纸条”比想象中更多。电影票票根上的序列号、超市小票底部的交易号、快递面单上的运单号——它们都独一无二地标识着某件事,但号码本身不携带任何描述信息。大数据仓库里,这类字段集中出现在四个高频场景。

第一个是电商订单号。订单事实表里存 order_id,查询“这笔订单的完整明细”时直接用订单号定位,不需要一张庞大的订单维度表。第二个是发票票据号,财务事实表里存 invoice_no,用于核销、对账、去重。第三个是物流运单号,运单事实表把 waybill_no 作为退化维度,方便按单还原包裹轨迹。第四个是交易流水号,支付事实表里的 transaction_id,是风控和清算系统关联各环节记录的钥匙。

这些场景有一个共同的角色定位:退化维度在事实表中承担着“定位、去重、关联外部系统”三大职责。它不能用于 SUM 这类数值聚合,但它能回答“这张订单是哪一笔”“这条流水有没有重复”“这笔交易在支付系统里长什么样”。

你可能会发现,这些“纸条”遍布业务系统的每个角落。下次建模时看到一串代表业务单号的字段,不妨先问一句:它能搬出什么属于自己的属性?搬不出来,就让它安安静静躺在事实表里当一张合格的“纸条”。

D退化∈{订单号, 发票号, 运单号, 流水号}D_{\text{退化}} \in \{ \text{订单号},\ \text{发票号},\ \text{运单号},\ \text{流水号} \}
退化维度常见于订单号、发票号、运单号、流水号这四类高基数单值标识字段,它们都满足“只标识、无属性”的特征。
  1. 典型的退化维度集合枚举了实践中最高频的四类退化维度,它们都属于业务过程的唯一标识。
    {订单号, 发票号, 运单号, 流水号}\{ \text{订单号},\ \text{发票号},\ \text{运单号},\ \text{流水号} \}
  2. 属于关系判断一个字段是否退化,就是看它是否落在这个“只标识、无属性”的集合语义内。
    ∈\in

对比缓慢变化维

仓库里最让管理员头疼的事,是客户搬家。三个月前登记的地址已经过时,可老地址对分析“去年区域订单量”还有用。管理员只能给档案卡加一行新记录,保留旧版本——这就是缓慢变化维(Slowly Changing Dimension,SCD)的日常工作。但请注意,客户档案会变,运单号却永远不会变。你从来不会看到“同一个运单号换了号码”这种事。

这正是退化维度与缓慢变化维的本质区别:SCD 存在的意义是追踪维度属性的历史变化,而退化维度压根没有属性,根本没有“变化”可以追踪。SCD 处理的是“有属性且属性会变”的维度,可以为它打上类型一、类型二、类型三的补丁;退化维度则完全不需要这套机制,它一旦生成就固定不变,天然免疫历史问题。

从建模决策看,两者是互斥的两条分支。拿到一个候选维度时,先看有无属性:无属性走退化的快车道;有属性再看属性是否变化:不变就做普通静态维度,变化就启用 SCD。千万别把两者混为一谈——给订单号字段硬套 SCD 类型二,等于给一张“纸条”写版本历史,徒劳无功。

所以,当有人问“退化维度要不要做缓慢变化维处理”时,你可以笑着反问:“运单号会自己换号码吗?”不会。既然不会变,就不需要历史版本。认清了“有属性的才谈变化,没属性的直接退化”,这两类维度就再也不会在模型里打架。

SCD(D): ∃ a∈Attr(D), 值(a,t1)≠值(a,t2)\text{SCD}(D):\ \exists\, a \in \text{Attr}(D),\ \text{值}(a, t_1) \neq \text{值}(a, t_2)
Degenerate(D): Attr(D)=∅\text{Degenerate}(D):\ \text{Attr}(D) = \varnothing
缓慢变化维要求存在某个属性随时间改变取值;退化维度的属性集为空,不存在任何可变化的属性。两者的前提条件互斥,设计时必须分道扬镳。
  1. 存在变化的属性SCD 要求维度中至少有一个属性在两个时间点的取值不同,这是它存在的根基。
    ∃ a∈Attr(D), 值(a,t1)≠值(a,t2)\exists\, a \in \text{Attr}(D),\ \text{值}(a, t_1) \neq \text{值}(a, t_2)
  2. 退化维度属性为空退化维度的属性集合是空集,没有属性自然没有变化需要记录。
    Attr(D)=∅\text{Attr}(D) = \varnothing
  3. 互斥关系一个有可追踪的变化、一个根本没有属性,两套机制不会同时作用于同一维度。
    SCD  ∩  Degenerate=∅\text{SCD} \;\cap\; \text{Degenerate} = \varnothing

建模实践

台账管理员终于要落笔了。那本厚厚的登记台账,每一行记录一笔业务事件,列头写着日期、客户、金额……还有一列,专门填运单号。这个运单号列,就是退化维度在事实表中的最终归宿。落笔时有三件事要注意:字段类型要对、位置要顺手、关系要理清。

字段设计上,退化维度直接以原始业务标识作为事实表的一列,与其他普通维度外键平级存放。它不需要代理键,不需要前缀 sk,保持与源系统一致的类型和长度——订单号是字符串就存字符串,别为了“节省空间”转成数值丢掉前导零。查询关联上,退化维度自带“免连接”属性:要按订单号查明细,直接 WHERE order_id = 'SO20240001' 即可,少一次 JOIN 就少一分等待。

从存储和性能角度看,退化维度带来的收益非常直观:省掉一张几十万行的维度表,省掉相关索引,省掉每次查询都要执行的维度表连接。事实表里多一个字段的成本微乎其微,却换来了更简单的 ETL、更快的查询、更少的出错点。整体来看,一个规范的事实表由三部分构成:度量、外键、退化字段。

台账合上的那一刻,管理员很满意:客户档案柜整整齐齐,运单号老老实实躺在台账里,既不占柜子,又能随时查到。这套“该建柜建柜、该落账落账”的功夫,就是数仓建模里化繁为简的艺术。

FactTable={M1,…,Mm,  K1,…,Kk,  D1,…,Dn}\text{FactTable} = \{ M_1, \dots, M_m,\; K_1, \dots, K_k,\; D_1, \dots, D_n \}
事实表的结构是“度量 + 外键 + 退化字段”三件套。退化字段与度量、外键平级存在,共同构成完整的事实表记录。
  1. 度量集合事实表中的数值指标,如订单金额、商品数量,用于聚合分析。
    M1,…,MmM_1, \dots, M_m
  2. 外键集合指向普通维度表(客户、商品、时间)的代理键,连接查询时使用。
    K1,…,KkK_1, \dots, K_k
  3. 退化字段集合直接内嵌在事实表中的业务标识,如订单号、流水号,无需外联。
    D1,…,DnD_1, \dots, D_n

AI 应用场景

电商实时推荐的订单事实表

阶段:特征工程与数据治理

解决的问题:传统做法为订单号单独建“订单维度表”,但订单号本身没有属性,导致维度表行数接近事实表、每次特征提取都要 JOIN,耗时成倍增长。AI 推荐系统的特征管道需要按订单粒度快速取数,退化维度设计让订单号直接内嵌事实表,省去 JOIN 环节。

具体案例:某电商平台的实时推荐特征平台每天处理千万级订单。订单号 order_id 作为退化维度直接存入订单事实表,特征管道按 order_id 分桶存储用户行为数据。算法工程师定位某笔订单的完整特征,只需在事实表上执行一行 WHERE 过滤,无需关联任何维度表,特征延迟从秒级降到毫秒级。

金融风控的交易流水还原

阶段:特征提取与模型训练

解决的问题:反欺诈模型需要把同一笔交易在支付、清算、账务三个子系统中的记录关联起来。如果为交易流水号建维度表,不仅无属性可存,还会让多表关联成为风控链路的性能瓶颈。

具体案例:某支付公司的交易事实表中,流水号 transfer_id 作为退化维度直入事实表。模型训练时,特征脚本按 transfer_id 拉取三张子系统的记录拼接成单笔交易的全链路特征,反欺诈模型能在 50 毫秒内完成一次风险评分,同时保证跨系统对账时流水号一一对应、无重复计数。

物流运单轨迹的智能还原

阶段:数据清洗与轨迹特征构建

解决的问题:物流 AI 需要对包裹时效做预测,核心输入是包裹全链路轨迹。运单号是天然的业务标识,若为它建维度表会引入无意义关联,拖慢轨迹还原任务。

具体案例:某物流公司的运单事实表把运单号 wb_no 作为退化维度,轨迹清洗任务按 wb_no 聚合各网点扫描记录,还原出“揽收—中转—派送—签收”的时间线。时效预测模型基于这份时间线抽取每个环节的耗时特征,准确率提升 12%,且不再需要维护一张上亿行的运单维度表。

Python 演示

python55 行
# -*- coding: utf-8 -*-"""退化维度判定与建模小工具"""  class Dimension:    """候选维度对象"""     def __init__(self, name, attrs):        self.name = name        self.attrs = attrs  class WarehouseDesigner:    """数仓建模助手: 决定维度落库方式"""     def __init__(self):        self.degenerate_list = []        self.dim_table_list = []        self.fact_fields = []     def decide(self, dim):        """核心决策: 属性为空则退化, 否则建维度表"""        if len(dim.attrs) == 0:            self.degenerate_list.append(dim.name)            self.fact_fields.append(dim.name)        else:            self.dim_table_list.append(dim.name)            self.fact_fields.append(dim.name + "_key")        return dim.name     def report(self):        print("=== 维度建模方案 ===")        print("退化维度(直接入事实表): " + ", ".join(self.degenerate_list))        print("普通维度(独立建维表): " + ", ".join(self.dim_table_list))        print("事实表最终字段: " + ", ".join(self.fact_fields))        saved = len(self.degenerate_list)        print("结论: 为 " + str(saved) + " 个无属性字段省去建表与连接开销")  def main():    designer = WarehouseDesigner()    dims = [        Dimension("订单号", []),        Dimension("客户号", ["姓名", "电话", "会员等级"]),        Dimension("商品号", ["品类", "单价"]),        Dimension("支付流水号", []),        Dimension("收货地址", ["省", "市", "详细地址"]),    ]    for dim in dims:        designer.decide(dim)    designer.report()  if __name__ == "__main__":    main()
目的:模拟数据建模师的决策过程,对五个候选维度执行“有属性建维表、无属性退化为事实表字段”的判定,并输出最终的建模方案。
  1. if len(dim.attrs) == 0:判断属性集合是否为空,这是“退化与否”的核心开关。
  2. self.degenerate_list.append(dim.name)记录退化维度,报告阶段汇总展示。
  3. self.fact_fields.append(dim.name + "_key")普通维度在事实表中只放外键,原数据去维表里查。
  4. Dimension("订单号", [])订单号没有任何属性,是典型的退化维度候选。
  5. for dim in dims:遍历所有候选维度,执行统一的建模决策策略。
  6. designer.decide(dim)逐维度调用决策函数,输出该字段的落库方式。

常见误区

误区数仓建模要求每个业务对象都有对应维度表,订单号应该建一张“订单维度表”,塞满各种字段才显得专业、规范。

正解订单号通常没有独立属性,强行建表就像给每张只有号码的小纸条开一个档案柜——占存储、拖查询、增维护。退化维度的核心思想恰恰是“不为空档案建柜子”,把订单号直接放事实表才是更规范的做法。规范与否,取决于是否贴合数据本质,而不是表面上的表数量。

为何常见:初学者容易把“事实表 + 维度表”的星形模型当成唯一教条,忽略了 Kimball 提出退化维度正是为了反对过度建模。

误区订单号在事实表里每行一个值,不就是主键吗?它就是个普通标识字段,不需要按“维度”对待。

正解退化维度在语义上是“维度”而不是“度量”,更不是主键。事实表主键是系统生成的代理键,用于物理定位一行记录;退化维度是业务标识,可参与 GROUP BY、WHERE 和跨系统关联,承载着业务语义。它的“退化”只是形态上不做成表,本质仍是维度。

为何常见:退化维度只剩一个字段,外表看起来和普通业务字段无异,容易让人忽略它的维度身份。

误区退化维度没有属性又不能 SUM,放进事实表纯属浪费存储空间,不如删掉。

正解退化维度最大的价值在“定位、去重、关联”。比如用订单号筛查某笔异常订单的完整事实记录、核对流水是否重复、把事实表与外部交易系统关联。没有它,事实表就是一堆无法追溯的数字,分析可信度无从谈起。

为何常见:人们习惯把维度理解为“可分组聚合的描述属性”,忽视了维度还有行级定位与审计追溯的功能。

误区订单状态、收货地址会变,我把它们拼进订单号字符串里,既留住了信息,又不用纠结退化维度,一举两得。

正解订单号作为业务标识必须保持稳定、单值、无业务语义。拼接状态或地址会破坏标识的唯一性与不变性,导致同一订单多次变化后号码漂移,后续对账与关联全面失控。正确的做法是:订单号做退化维度,订单状态等可变属性单独建模并考虑使用缓慢变化维。

为何常见:混淆了“维度的键”和“维度的属性”,把键和属性塞进同一个字段,让标识承载了不该承载的信息。

面试题

Q1. 退化维度最核心的判定条件是?

单选题 · easy

  • A.字段的基数非常高
  • B.维度没有任何属性← 正确答案
  • C.字段属于数值类型
  • D.维度来自业务系统

答案:B。退化维度的关键标志是“没有可描述的属性”——就像运单号只有号码本身。基数高、数值类型、来自业务系统都只是表象,不能作为判定依据。

Q2. 下列哪个字段最适合做退化维度处理?

单选题 · easy

  • A.客户姓名
  • B.订单号← 正确答案
  • C.商品分类
  • D.会员等级

答案:B。订单号只有标识作用、没有描述属性,适合退化;客户姓名、商品分类、会员等级都是描述属性,应放入对应维度表供分组分析。

Q3. 退化维度在事实表中的存储方式是?

单选题 · easy

  • A.生成代理键并存入维度表
  • B.以原值直接作为事实表字段← 正确答案
  • C.只保留哈希值并丢弃原值
  • D.拆分存储到多个子表中

答案:B。退化维度的设计主张“不建表、直接存”,以业务原值作为事实表字段,保留可读性和可追溯性,既不做代理键也不做哈希。

Q4. 关于退化维度与缓慢变化维的区别,正确的是?

单选题 · mid

  • A.两者都需跟踪维度的属性变化
  • B.退化维度没有属性所以没有变化可追踪← 正确答案
  • C.缓慢变化维不需要保存任何历史
  • D.退化维度必须使用类型二去处理

答案:B。缓慢变化维的核心是追踪属性历史;退化维度属性集为空,没有“变化”可追踪,因此与 SCD 互斥,不能套用类型二机制。

Q5. 下列哪些字段通常可判断为退化维度?

多选题 · mid

  • A.快递运单号← 正确答案
  • B.支付流水号← 正确答案
  • C.用户收货地址
  • D.电子发票号码← 正确答案

答案:ABD。运单号、支付流水号、发票号码都是不带描述属性的唯一标识,适合退化;收货地址是可供分组统计的业务属性,应进维度表。

Q6. 退化维度的设计原则包括?

多选题 · mid

  • A.不为无属性的字段强行建表← 正确答案
  • B.字段命名清晰且有业务含义← 正确答案
  • C.必须为它建立代理键
  • D.严格保留字段的唯一单值← 正确答案

答案:ABD。退化维度的原则是“不建表、不设代理键、保留原值与单值特性”,命名规范保证字段可读,强行建代理键反而丢失业务可追溯性。

Q7. 判断某字段建维度表还是退化成字段,根本依据是?

单选题 · mid

  • A.该字段是否为表的主键
  • B.该字段是否存在独有属性← 正确答案
  • C.该字段的字符长度大小
  • D.该字段是否允许为空值

答案:B。有独有属性才值得建维度表,没有属性就该退化。是否主键、字符长短、能否为空都与“有无属性”无关,不能作为判断依据。

Q8. 对已退化的订单号做分析,下列查询最合理的是?

单选题 · hard

  • A.对订单号做 SUM 聚合运算
  • B.按订单号定位并关联外部系统← 正确答案
  • C.把订单号改名成订单数值
  • D.为订单号单独建立维度表

答案:B。订单号是维度标识,宜做定位、筛选、跨系统关联,不宜做数值聚合;正确设计下也无需再补建维度表,改名更是无意义操作。

Q9. 关于退化维度本质的说法,正确的是?

多选题 · hard

  • A.退化维度就是事实表主键
  • B.退化维度本质是维度而非度量← 正确答案
  • C.退化维度的属性集合为空集← 正确答案
  • D.退化维度完全无法参与查询

答案:BC。退化维度是属性为空集的维度,能参与定位、分组、关联查询,并不等同于事实表主键——主键是系统行标识,退化维度是业务标识。

Q10. 某事实表已含订单号退化维度,现需新增“订单状态”并跟踪其历史变化,最优做法是?

单选题 · extreme

  • A.将状态信息直接拼入订单号
  • B.新建订单维表并采用缓慢变化维← 正确答案
  • C.在事实表加状态字段且覆盖旧值
  • D.生成随机标识替代原订单号

答案:B。订单状态是有属性且需追踪历史的维度,应建订单维表并用 SCD 保存历史版本;拼入订单号会破坏标识稳定性,事实表覆盖旧值丢失历史,随机替代更不可取。