2、报表数据模型设计:星型模型与雪花模型、事实表与维度表设计、数据粒度概念、在ERP中如何设计订单分析模型
好,咱们进入第二章。这一章可以说是报表引擎的「地基工程」。
我见过太多团队,一上来就写SQL,报表跑得飞快。等数据量上来了,查询慢得像蜗牛,改都没法改。为什么?数据模型没设计好。
说白了,报表好不好用,七成取决于数据模型。今天咱们就把星型模型、雪花模型、事实表、维度表、数据粒度这几个核心概念掰开揉碎讲清楚。
2.1 星型模型 vs 雪花模型:选哪个?
先问个问题:你见过仓库里的货架吗?
星型模型就像一个大货架,中间放核心数据(事实),四周挂着小标签(维度)。雪花模型呢?它把标签又细分了,像树枝一样分叉出去。
核心区别一句话:
- 星型模型:事实表在中间,维度表直接连在周围。简单、查询快。
- 雪花模型:维度表继续拆分,形成多层结构。节省存储,但查询慢。
我在项目中遇到过一件事。有个客户做电商报表,用了雪花模型,把「地区」拆成省、市、区三级。结果每次跑全国销售汇总,要关联5张表,查询时间从2秒变成20秒。后来改成星型模型,把省市区合并成一张维度表,查询直接回到2秒。
你想想看,报表引擎最怕什么?怕慢。所以我个人习惯,90%的场景用星型模型。除非你存储空间极度紧张,否则别碰雪花。
我的建议:
ERP报表引擎,优先选星型模型。简单、高效、好维护。雪花模型只在你需要严格规范化、且查询频率不高时考虑。
2.2 事实表与维度表:报表的「骨架」和「血肉」
这两个概念,我换个说法你马上懂。
事实表:记录「发生了什么」。比如一笔订单、一次入库、一次付款。它里面全是数字和ID。
维度表:描述「是谁、在哪、什么时候」。比如客户姓名、产品名称、日期。
举个例子,订单分析模型:
| 表类型 | 表名 | 字段示例 |
|---|---|---|
| 事实表 | fact_order | order_id, customer_id, product_id, amount, quantity, order_date |
| 维度表 | dim_customer | customer_id, name, city, level, phone |
| 维度表 | dim_product | product_id, name, category, price, supplier |
| 维度表 | dim_date | date_key, year, month, day, quarter, week |
嗯,这里要注意:事实表里的ID,一定要和维度表的主键对应。我曾经见过一个项目,事实表用「订单编号」做关联,维度表用「自增ID」,结果两张表永远对不上。排查了三天,最后发现是设计时没统一规范。
避坑指南:
我曾经犯过一个错:在事实表里直接存「客户姓名」而不是「客户ID」。结果客户改名了,历史报表全乱套。记住:事实表只存ID,所有描述信息放维度表。
2.3 数据粒度:你的报表「精细」到什么程度?
数据粒度,说白了就是「每行数据代表什么」。
举个例子:
- 订单级粒度:一行数据 = 一笔订单。适合看订单总数、总金额。
- 订单行级粒度:一行数据 = 订单中的一行商品。适合看每个商品的销量。
- 日汇总粒度:一行数据 = 一天的总销售额。适合看趋势。
我建议你记住这个原则:粒度越细,灵活性越高,但数据量越大。
在ERP中,订单分析模型通常选「订单行级粒度」。为什么?因为ERP需要知道每个订单里每个商品的销售情况。如果你只存订单级,想分析「哪个SKU卖得好」就得重新算,很麻烦。
粒度选择口诀:
看明细,用行级;看趋势,用汇总;看全貌,用订单级。
宁细勿粗,粗了改不了,细了可以聚合。
2.4 在ERP中如何设计订单分析模型
好,理论讲完了,咱们来点实战。这是我在一个中型制造企业ERP项目中的真实设计。
第一步:确定业务过程
订单分析,核心业务过程就是「下单」和「发货」。所以我们设计两张事实表:
fact_order:记录下单事件fact_delivery:记录发货事件
第二步:确定粒度
订单表用「订单行级粒度」。每行数据代表一个订单中的一行商品。
第三步:设计维度表
我们需要这些维度:
dim_customer:客户信息dim_product:产品信息dim_date:日期信息dim_employee:销售人员dim_warehouse:仓库信息
第四步:建表SQL示例
-- 事实表:订单行级
CREATE TABLE fact_order (
order_line_id INT PRIMARY KEY,
order_id INT,
customer_id INT,
product_id INT,
employee_id INT,
warehouse_id INT,
order_date_key INT,
quantity DECIMAL(10,2),
unit_price DECIMAL(10,2),
discount DECIMAL(10,2),
line_amount DECIMAL(10,2)
);
-- 维度表:客户
CREATE TABLE dim_customer (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(100),
city VARCHAR(50),
province VARCHAR(50),
customer_level VARCHAR(20),
created_date DATE
);
-- 维度表:产品
CREATE TABLE dim_product (
product_id INT PRIMARY KEY,
product_name VARCHAR(100),
category VARCHAR(50),
brand VARCHAR(50),
unit_price DECIMAL(10,2)
);
-- 维度表:日期
CREATE TABLE dim_date (
date_key INT PRIMARY KEY,
full_date DATE,
year INT,
month INT,
day INT,
quarter INT,
week_of_year INT
);
实战小技巧:
日期维度表我建议一次性生成10年的数据。别问我为什么,我曾经因为日期表没预生成,导致报表跑不出来,被老板骂了一下午。预生成后,查询直接用date_key关联,快得飞起。
第五步:设计汇总表(可选)
如果报表需要频繁查询「每日销售额」,可以建一张汇总表:
CREATE TABLE fact_daily_sales (
date_key INT,
total_amount DECIMAL(12,2),
order_count INT,
customer_count INT,
PRIMARY KEY (date_key)
);
这样,日报查询直接查汇总表,不用每次都扫描几百万行的明细表。
2.5 总结一下
这一章内容不少,我帮你捋一捋:
- 星型模型:简单快速,首选。
- 雪花模型:省存储但慢,少用。
- 事实表:存事件,只放ID和数字。
- 维度表:存描述,放文本和属性。
- 数据粒度:宁细勿粗,细了可以聚合。
- 订单分析模型:订单行级粒度 + 星型模型 + 预生成日期表。
下一章,咱们聊聊ETL流程设计。说白了,就是怎么把ERP里的脏数据洗干净,装进咱们设计好的模型里。到时候见。
公众号:蓝海资料掘金营,微信deep3321