2. 核心概念

好,咱们正式开始聊语义层的核心概念。说实话,我见过不少团队,一上来就急着写 SQL,结果业务方问一句「上个月的毛利率是多少」,就得改半天代码。为什么?因为底层没有把这些概念理清楚。

我个人习惯,在设计语义层之前,先把五个概念写在白板上:维度、度量、粒度、层次结构、计算成员。这五个词,就是语义层的「五官」。你想想看,五官不正,后面怎么化妆都别扭。

2.1 维度:你从哪个角度看数据?

维度,说白了就是「观察数据的角度」。比如「时间」、「地区」、「产品类别」——这些都是维度。它们回答的是「谁、什么、何时、何地」这类问题。

我在项目中遇到过最典型的坑:有人把「订单状态」和「支付状态」混在一个字段里。结果想统计「已支付未发货」的订单时,SQL 写得跟绕口令似的。嗯,这里要注意——每个维度应该只描述一个业务视角。

维度的核心特征:

  • 离散性:取值是有限的、可枚举的(比如省份、月份)
  • 描述性:提供上下文,不参与计算(「北京」不能加减)
  • 层次性:可以向上或向下钻取(年→季度→月)

举个例子,一个「日期」维度,它的值可能是 2024-01-15。但你不会拿这个值去做加法,而是用它来筛选、分组、或者做趋势分析。

2.2 度量:你到底想算什么?

度量就是你要计算的数值。销售额、订单量、库存周转天数——这些都是度量。它们回答的是「多少」的问题。

度量有个关键属性:可加性。我习惯把度量分成三类:

类型 说明 例子
完全可加 跨所有维度都能直接求和 销售额、订单数量
半可加 只能沿部分维度求和 库存量(不能跨时间求和)
不可加 不能直接求和 比率、单价、排名

我曾经帮一个零售客户排查报表,发现「库存周转天数」在汇总时直接求和了。结果集团看全国数据,显示周转天数 300 多天——这明显不对。后来改成加权平均,才恢复正常。

我的经验:定义度量时,一定要标注它的聚合方式。是 SUM、AVG、COUNT,还是更复杂的加权?写清楚,后面少踩一半的坑。

2.3 粒度:一行数据代表什么?

粒度,是语义层里最容易被忽略、但后果最严重的概念。它回答的是「每一行数据到底描述的是哪个级别的业务事件」。

举个例子:

  • 「每笔订单一行」——粒度是订单
  • 「每笔订单中的每个商品一行」——粒度是订单明细
  • 「每个商品每天的库存快照一行」——粒度是商品+日期

你想想看,如果把订单明细和订单汇总混在一起做分析,那结果能对吗?我见过一个 BI 项目,就是因为粒度没对齐,导致「订单总数」和「商品销售件数」在同一个报表里差了 10 倍。排查了三天,最后发现是事实表关联时粒度膨胀了。

避坑指南:我曾经在金融项目中,把「交易流水」和「账户余额」放在同一个查询里。结果余额被重复加了好几遍。记住:不同粒度的事实表,不要直接 JOIN 后做聚合。要么先聚合再关联,要么用子查询隔离。

2.4 层次结构:钻取与上卷的骨架

层次结构,就是维度内部的组织关系。比如「年→季度→月→日」,或者「国家→省份→城市→门店」。

语义层里定义好层次结构,业务用户就能自由钻取。点一下「华北」,展开看到北京、天津、河北——这种体验,底层靠的就是层次结构。

我建议在建模时,把层次结构分成两类:

  • 平衡层次:每一层的深度相同(比如日期维度,每层都有固定的下级)
  • 参差不齐层次:某些分支的深度不同(比如组织架构,有的部门有 5 级,有的只有 3 级)

处理参差不齐层次时,我习惯用「桥接表」或者「路径枚举」的方式。嗯,这个后面讲高级建模时会细说。

2.5 计算成员:不存数据,却能算数据

计算成员,就是那些不在原始表中、但通过已有度量计算出来的「虚拟度量」。比如「利润率 = 利润 / 销售额」、「同比增长率 = (本期 - 同期) / 同期」。

它的好处很明显:

  • 数据不用重复存储
  • 计算逻辑统一,不会出现「A 部门用除法,B 部门用减法」的混乱
  • 修改公式时,只改一处,全局生效

我在项目中遇到过最典型的场景:财务部门要求「毛利率」保留两位小数,但销售部门要四位。如果各自写 SQL,迟早会出不一致。后来在语义层里统一用一个计算成员,两边引用同一个定义,问题就解决了。

计算成员的典型写法(以 MDX 为例):

MEMBER [Measures].[毛利率] AS
  [Measures].[毛利] / [Measures].[销售额],
  FORMAT_STRING = '0.00%'

在 SQL 语义层中,通常用 WITH 子句或视图来实现类似效果。

2.6 五个概念的关系图

下面这张图,是我每次培训时必画的。它把五个概念串在了一起:

语义层核心概念关系图 事实表(度量) 时间维度 产品维度 地区维度 渠道维度 层次结构:年→季→月→日 层次结构:国家→省→市→店 计算成员:毛利率 粒度:订单明细 度量 维度 粒度 层次结构 计算成员

你看,事实表在中间,四周是维度,头顶是粒度,脚下是计算成员,两侧是层次结构。这五个概念一旦对齐,整个语义层就稳了。

2.7 小结:先画图,再写代码

我个人习惯,每接手一个新项目,第一件事不是打开 SQL 客户端,而是拿白板把这五个概念画一遍。维度有哪些?度量怎么聚合?粒度是什么?层次结构怎么走?计算成员需要几个?

这些问题想清楚了,后面的建模、ETL、报表开发,都是水到渠成的事。你想想看,如果连「一行数据代表什么」都没搞明白,写出来的查询能靠谱吗?

一个小技巧:下次开会讨论报表需求时,试着用这五个概念去拆解业务方的描述。你会发现,很多模糊的需求一下子就清晰了。比如对方说「我要看每个月的销售情况」,你可以追问:「这个『销售情况』是指订单金额还是利润?粒度是按订单还是按商品?」——几句话就能把需求定死,避免后期返工。