1. 维度建模基础概念陷阱:混淆事实表与维度表
说实话,我见过太多数据团队在这个坑里摔得鼻青脸肿。明明业务需求梳理得挺清楚,一到建表就乱了套——把用户信息塞进事实表,把交易金额扔进维度表。结果呢?模型跑起来慢得像蜗牛,业务方要个报表得等半天。
为什么会这样?说白了,就是没搞明白事实表和维度表各自的定位。我刚开始做数仓时也犯过这毛病,后来被一个老前辈点醒,才真正理解这两者的区别。
事实表 vs 维度表:一张表说清楚
| 对比维度 | 事实表 | 维度表 |
|---|---|---|
| 核心作用 | 记录业务事件 | 描述业务对象 |
| 数据特征 | 数值型、可加性 | 文本型、描述性 |
| 数据量 | 快速增长,通常很大 | 相对稳定,变化缓慢 |
| 主键 | 复合主键(外键组合) | 单一主键(代理键) |
| 更新方式 | 追加写入,极少修改 | 缓慢变化维(SCD) |
| 典型例子 | 订单金额、销售数量 | 客户姓名、产品分类 |
记住这个口诀:事实表回答"发生了什么",维度表回答"谁、什么、在哪、何时"。
最常见的混淆场景
我在项目中遇到过好几次这样的场景:业务方说"我要看每个客户的购买金额",结果建模的同学直接把客户姓名、年龄、性别全塞进了事实表。你想想看,这样做会有什么后果?
- 数据冗余爆炸:同一个客户买100次,他的信息就重复存100次
- 更新维护噩梦:客户改个手机号,得扫全表更新,性能直接崩
- 查询效率低下:事实表膨胀得飞快,扫描成本成倍增加
嗯,这里要注意,不是所有数值都该进事实表。比如产品单价,虽然是个数字,但它描述的是产品属性,应该放在产品维度表里。只有那些随业务事件变化的数值,比如成交金额、折扣金额,才属于事实表。
一个真实的错误案例
我记得有个电商项目,团队把订单明细和商品信息混在一个表里。表结构大概长这样:
-- 错误的做法:事实和维度混在一起
CREATE TABLE order_mixed (
order_id STRING,
customer_name STRING, -- 维度属性
customer_level STRING, -- 维度属性
product_name STRING, -- 维度属性
product_price DECIMAL, -- 维度属性
order_amount DECIMAL, -- 事实度量
order_qty INT, -- 事实度量
order_date DATE -- 维度属性
);
这个表跑了一个月,数据量从100万涨到5000万。每次查某个客户的购买记录,都得扫全表。更可怕的是,商品调价后,历史数据全得跟着改——你敢信?
正确的做法应该是拆成两张表:
-- 维度表:客户
CREATE TABLE dim_customer (
customer_sk INT PRIMARY KEY,
customer_name STRING,
customer_level STRING,
effective_date DATE,
expired_date DATE
);
-- 维度表:产品
CREATE TABLE dim_product (
product_sk INT PRIMARY KEY,
product_name STRING,
product_price DECIMAL,
category STRING
);
-- 事实表:订单
CREATE TABLE fact_order (
order_id STRING,
customer_sk INT, -- 外键
product_sk INT, -- 外键
order_amount DECIMAL, -- 事实
order_qty INT, -- 事实
order_date DATE,
FOREIGN KEY (customer_sk) REFERENCES dim_customer(customer_sk),
FOREIGN KEY (product_sk) REFERENCES dim_product(product_sk)
);
个人习惯:我每次建模前都会先问自己三个问题——这个数据是描述业务对象的吗?它会频繁变化吗?它是不是文本描述?如果三个都是,那它大概率是维度属性。
核心知识体系
下面这张图是我自己总结的,帮你一眼看透事实表和维度表的关系:
避坑指南
我曾经踩过的坑:有个金融项目,我把交易渠道的描述信息(渠道名称、渠道类型、渠道负责人)全塞进了交易事实表。结果渠道改名时,要更新上亿条历史数据,跑了一整晚还没跑完。后来改成维度表,只改一条记录就搞定了。
给你几个实用的判断方法:
- 看数据变化频率:每天变几次的,大概率是事实;几个月才变一次的,大概率是维度
- 看数据用途:用来做聚合计算的,进事实表;用来做筛选分组的,进维度表
- 看数据来源:来自业务流水表的,进事实表;来自基础信息表的,进维度表
我的小技巧:建模时先画一张星型模型草图,把业务事件放在中间,周围画上相关的业务对象。如果某个字段你犹豫不决,就问自己——"这个字段会随着每次交易变化吗?" 会,就放事实表;不会,就放维度表。
记住,维度建模不是死板的教条。但事实表和维度表的边界,是不能模糊的底线。搞混了,后面所有ETL、报表、分析都会跟着乱。我见过太多项目因为这个基础问题,最后不得不推倒重来。