概述
数据中心模型指维度建模(KimBall),即基于事实表、维度表构建星型/雪花/星座模型。
模型设计原则
遵循这些原则可以使模型稳健且简单。稳健的模型能够满足用户提出任意维度分析,灵活适应未来的数据变化,降低维护成本。简单的模型能让用户更好的理解业务,更重要的是,能够减少性能压力。
原则1 通过事实表和维度表关联来实现不同事实表之间的关联分析
比如计算目标达成率场景,基于两个事实表(目标事实表和销售事实表)的事实字段计算,两个事实表分别与日期维度表、产品维度表关联,就可以实现每月每个产品的目标达成率分析。即通过事实表分别与维度表的关联来实现不同事实表的关联分析。
多个事实表包含的同一维度则必须建立维度表,某事实表特有的维度可以不建维度表。在上述场景中,如果不需要进行不同产品的目标达成率分析,那么产品维度可作为退化维度存在于销售事实表中,无需新建产品维度表。如果需要分析,那必须新建产品维度表。
原则2 为了维度统一,维度属性字段设计在维度表中,事实表尽量只保留维度主键
事实表不建议包含已有维度主键的其他维度字段,其他维度字段建议设计在维度表中。这样做主要是为了保持维度的一致性。比如销售事实表中只保留[商品id](商品的唯一主键),而不保留[商品名称]字段,[商品名称]字段统一放在商品维度表中。
有些维度没有维度主键或维度表,则作为退化维度设计在事实表中(退化维度指没有维度表的维度属性)。比如电商平台的搜索词,一般只保留在搜索事实表中,没有专门的搜索词维度表。
特殊场景下事实表无法做到只有维度主键,比如目标达成率场景(见下面案例1)只能通过维度属性关联,这个在案例1中详细解释。
原则3 事实表尽量仅保留最细粒度的事实
越细粒度的事实表支撑的分析维度越多,通过使用原子粒度的事实表建模满足未来用户灵活的过滤和分组分析需求,更好的支撑各种下钻分析场景。这样也可以减少不同粒度数据带来的口径不一致问题。
如果实际分析时,不同粒度的指标业务含义不同,也可以同时保留,但在指标层面是两个指标。比如基于商品销售事实表中销售额字段计算出来的店铺销售额,和电商平台后台计算出的店铺销售额不一样,业务含义不一样,实际分析时可能都需要,那就两个事实表都保留,但在指标层面是两套指标。
原则4 事实表中的事实只保留原子指标(不能被其他指标加工得到的指标)
比如目标达成率,建议事实表中只保留原子指标(销售额和目标值),目标达成率通过在数据中心平台内的指标管理添加。
再比如总成本=销售费用+研发费用,总成本指标也在数据中心的指标管理通过公式添加。以此灵活满足不同维度下的指标分析需求,无需创建多个不同粒度的指标,保证指标的一致性。
以上原则,优先满足原则1和原则2,原则1和2是模型构建的基本原则。为了模型更好的满足分析需求,建议遵循原则3和4。
最后,我们建议用户构建星型模型而非雪花模型,牺牲一些存储资源来提升性能。
指标维度公式
说明
指标分类 | 案例 |
---|---|
原子指标 | GMV=成交金额 |
复合指标 | 总成本=sum(销售成本)+sum(研发成本)+sum(材料成本) |
成交转化率=sum(支付买家数)/sum(访客数) | |
衍生指标-维度过滤指标 | A产品销售额=def_add(sum(销售额),[],[产品类别="A"]) |
衍生指标-同期环期累计值类 | 去年同期销售额=def_add(sum(销售额),[],[year(年月)=earlier(Year(年月)-1),month(年月)=earlier(month(年月))]) |
上月环期销售额=def_add(sum(销售额),[],[year(年月)=earlier(Year(年月)),month(年月)=earlier(month(年月)-1)]) | |
年累计(ytd)=def_add(sum(销售额),[],[year(年月)=earlier(Year(年月)),month(年月)<=earlier(month(年月))]) |
建议
建议指标中引用的指标尽量来源于已创建好的指标,而不是事实表中的字段。这样做的好处是便于后续的维护,一旦基础指标的逻辑发生变更,只需改基础指标的逻辑,其他指标计算逻辑都能同步刷新。
常见问题
Q:二次加工维度(动态维度)如何处理?
A:平台支持添加动态维度,比如客户类型=if(sum(签单金额)>1000,"重点客户","非重点客户")
Q:指标的加工逻辑是写在事实表中还是写在平台的指标管理公式中?
A:建议把指标的加工逻辑写在平台内,这样利于指标计算口径和血缘的查看。但如果指标的计算公式特别复杂,且指标口径相对固化,也可以加工在事实表中,指标管理直接引用事实表中的字段。
Q:一个指标不同维度下的计算方式不同如何处理?
A:比如每个产品的销售金额等于合同的签单总额按产品汇总,每个销售人员的销售额等于合同金额分配给该销售人员的金额,而不是签单总额。这种情况下同样是销售额指标,产品维度下和人员维度下是不同的计算方式,我们建议建两个指标即[产品_销售额]、[销售人员_销售额]
模型常见案例速查
以上的模型基本原则可以解决 80% 以上的场景,还有一些场景相对复杂,提供一些案例速查。
案例1 维度表和事实表N:N关联(目标达成率分析场景)
如图,店铺目标_事实表只有年月粒度的,做不到日期粒度。那么通过事实表的年月字段和日期_维度表的年月字段做N:N的关联,计算[目标达成率]=sum(销售额)/sum(目标值)
Q:为什么通常用维度主键关联事实表,不用维度属性关联事实表?
A:目标达成率计算场景中,每个年月属性值对应的日期都是唯一的,在事实表计算时不会造成数据的膨胀,所以可以直接用维度属性关联事实表。
案例2 维度层次关系1:N
维度层次关系一般有两种处理方式:
第一种方式:将高维的维度属性冗余在低维的维度表中,比如战区:销售=1:N,将战区id、战区名称等战区的维度属性冗余在销售人员维度表中
第二种方式:雪花模型,比如「客户:客户的联系人」=1:N,分别新建客户维度表和客户联系人维度表,建立这两个维度表的 1:N 关联关系。
很明显,第一种方式占用更多的存储资源,第二种查询性能不如第一种好,通常我们建议第一种方案,性能提升优先级高于存储资源耗费。
选择这两种方案,除了要权衡存储和性能,还要看事实表的粒度,如果事实表大部分是到低维粒度(比如,战区:销售=1:N),那么建议第一种方案;如果事实表粒度大部分是到高维粒度(比如,客户:客户的联系人=1:N),那么建议选择第二种。
案例3 维度N:1且1:N
如图,每个客户对应多个渠道伙伴,事实表只到客户粒度没有到渠道伙伴粒度,需要计算每个渠道伙伴分类下的签单金额:
案例4 维度角色扮演
同一个事实表中有不同的日期计算,在不同场景下基于不同日期字段分析。比如订单表中有下单日期和发货日期,分析每月下单的订单数和发货的订单数。
两个方案:
拆分成多个事实表:将订单事实表拆分为下单事实表和发货事实表,日期字段在不同事实表中分别存储,分别关联日期维度表。
建立多个维度表:建立多个日期维度表,订单表的下单日期和发货日期分别与这两个日期维度表关联。
案例5 维度映射(不同维度主键同一维度属性联合分析)
如图,产品维度表和产品线维度表中都有产品线名称,产品维度和产品线维度表不是层次关系。需要分析不同产品线的目标达成率=sum(销售金额)/sum(目标值)
处理方案:将产品维度表和产品线维度表上下合并,产品线名称字段合并,产品id和产品线id字段不合并,分别与事实表建立1:N关系。如图:
案例6 维度N:N关系(桥接表)
维度之间不是1:N关系,而是N:N的关系。通过新建桥接表来建模,桥接表指维度匹配关系表,只有维度主键字段。
(目前暂无实施案例)
案例7 维度1:N:Nⁿ且1:Nⁿ
公司、机会、合同维度不是标准的层次关系:
这种情况下,如果参考桥接表的理论,新建以合同 id 为主键的合同、机会、公司关系匹配表,这张匹配表再分别关联合同维度表、机会维度表、公司维度表。
但这个场景和桥接表的使用场景又略有不同,这里只有一对多,不存在对多对的关系。为了提升查询的性能,我们建议将关联关系冗余在事实表中,建立标准的星型模型。
拓展阅读
IT 如何理解业务梳理模型
模型设计之前先要梳理梳理总线矩阵,即梳理业务事实、维度和两者之间的关系。
总线矩阵示例:
日期 | 客户 | 产品 | 销售代理 | 仓库 | 运货商 | |
---|---|---|---|---|---|---|
报价 | X | X | X | X | ||
下单 | X | X | X | X | ||
运输至客户 | X | X | X | X | X | X |
接受付款 | X | X | X | |||
客户退货 | X | X | X | X | X | X |
梳理总线矩阵需要理解业务场景。如果是作为纯IT或数据开发人员,理解业务场景有两种方式:
看分析看板,主要看分析内容是通过哪些基础表做了哪些处理得到的。这个方式往往比较耗时,因为如果客户之前是用BI做的分析,大概率嵌套了层层宽表,要打开每一层的数据集看里面的处理过程。
和业务数据管理员(既理解业务又理解数据的人)一起基于一些关键分析指标和表来看,一般情况下业务BP提供的指标和表基本可以覆盖用户的分析场景,且还有一个好处是业务数据管理员知道数据的加工过程,后续模型设计出来数据如何更好的加工也可以提供建议。所以这种方式效率比较高。
在理解业务场景的过程中,就可以开始梳理总线矩阵了:
如果自己去看分析内容,可以先罗列有哪些业务过程(事实表),然后看业务过程中包含哪些维度和基于哪些维度去做分析。
如果是和业务数据管理员一起看关键的分析表和表,那事实表可以基于关键的分析表,维度可以先罗列一些,在梳理事实表的过程中再不断补充维度。将事实和维度之间的相关性标记下来。
总线矩阵梳理之前想尝试不基于具体的分析内容或表来梳理,而是基于一些业务流程,即打算先基于业务建空模型。发现这样梳理不下去,遇到的阻塞主要在于:
对于IT(不理解业务)来说,梳理业务过程不能完全基于业务流程来,业务流程中关联的维度也不清晰
对于业务数据管理员(理解业务)来说,光和他将模型的概念有些抽象,他还是不知道怎么干
总线矩阵梳理完后,我们得到事实和维度的关联关系,模型的基本框架就出来了。结合上面说的基本原则,思考维度和事实之间的关系就能构建出稳健的模型了。