4. 维度建模实战:采购日期维度、供应商维度、物料维度、采购组织维度的星型模型设计
在采购支出数据仓库中,星型模型是最常用的维度建模方法。它以事实表为中心,周围环绕多个维度表,形成星状结构。本章将围绕采购支出分析的核心需求,详细设计采购日期维度、供应商维度、物料维度和采购组织维度,并构建完整的星型模型。
4.1 星型模型总体架构
采购支出星型模型以采购支出事实表为中心,连接四个核心维度表。事实表存储可量化的采购指标(如金额、数量、单价),维度表提供描述性属性(如日期、供应商名称、物料分类)。
设计原则:
- 事实表尽量轻量,只保留外键和度量值。
- 维度表尽量宽表化,包含所有可能的分析属性。
- 每个维度表有独立的代理键(Surrogate Key),与业务主键解耦。
4.2 采购日期维度设计
日期维度是数据仓库中最通用的维度之一。在采购场景中,日期维度支持按年、季度、月、周、日进行采购趋势分析。
| 字段名 | 数据类型 | 说明 | 示例 |
|---|---|---|---|
| date_sk | INT | 代理键,自增主键 | 20250101 |
| full_date | DATE | 完整日期 | 2025-01-15 |
| year | INT | 年份 | 2025 |
| quarter | INT | 季度(1-4) | 1 |
| month | INT | 月份(1-12) | 1 |
| month_name | VARCHAR(10) | 月份名称 | January |
| week_of_year | INT | 年内第几周 | 3 |
| day_of_week | INT | 周内第几天(1=周一) | 3 |
| is_weekend | BOOLEAN | 是否周末 | false |
| is_holiday | BOOLEAN | 是否法定假日 | false |
设计要点:日期维度建议一次性生成未来10年的数据,避免ETL运行时动态补录。代理键建议使用YYYYMMDD格式的整数,便于排序和分区。
4.3 供应商维度设计
供应商维度是采购分析的核心维度之一,支持供应商绩效评估、支出集中度分析、风险监控等场景。
| 字段名 | 数据类型 | 说明 | 示例 |
|---|---|---|---|
| supplier_sk | INT | 代理键,自增主键 | 1001 |
| supplier_code | VARCHAR(20) | 业务系统供应商编码 | SUP-00123 |
| supplier_name | VARCHAR(100) | 供应商全称 | XX科技股份有限公司 |
| region | VARCHAR(50) | 所属区域 | 华东 |
| country | VARCHAR(50) | 国家 | 中国 |
| supplier_tier | VARCHAR(10) | 供应商等级(A/B/C) | A |
| risk_level | VARCHAR(10) | 风险等级(高/中/低) | 低 |
| payment_terms | VARCHAR(50) | 付款条件 | Net 30 |
| is_active | BOOLEAN | 是否启用 | true |
| effective_date | DATE | 生效日期 | 2024-01-01 |
| expiry_date | DATE | 失效日期 | 9999-12-31 |
缓慢变化维度(SCD)处理:供应商维度通常采用SCD Type 2策略。当供应商名称、等级或风险级别发生变化时,生成新记录并更新生效/失效日期,保留历史快照。
4.4 物料维度设计
物料维度描述采购物料的属性,支持按物料类别、规格、单位等维度进行支出分析。
| 字段名 | 数据类型 | 说明 | 示例 |
|---|---|---|---|
| material_sk | INT | 代理键,自增主键 | 2001 |
| material_code | VARCHAR(20) | 物料编码 | MAT-04567 |
| material_name | VARCHAR(100) | 物料名称 | 不锈钢板 304 2mm |
| category_l1 | VARCHAR(50) | 一级分类 | 原材料 |
| category_l2 | VARCHAR(50) | 二级分类 | 金属材料 |
| category_l3 | VARCHAR(50) | 三级分类 | 不锈钢板 |
| unit | VARCHAR(10) | 计量单位 | 吨 |
| specification | VARCHAR(200) | 规格描述 | 304/2mm/1219x2438 |
| is_procurable | BOOLEAN | 是否可采购 | true |
4.5 采购组织维度设计
采购组织维度描述企业内部采购管理架构,支持按公司、部门、采购组进行支出分摊分析。
| 字段名 | 数据类型 | 说明 | 示例 |
|---|---|---|---|
| org_sk | INT | 代理键,自增主键 | 3001 |
| org_code | VARCHAR(20) | 组织编码 | ORG-CN-SH |
| org_name | VARCHAR(100) | 组织名称 | 上海采购中心 |
| company | VARCHAR(50) | 所属公司 | XX集团中国有限公司 |
| department | VARCHAR(50) | 所属部门 | 供应链管理部 |
| cost_center | VARCHAR(20) | 成本中心编码 | CC-SH-001 |
| region | VARCHAR(50) | 所属区域 | 华东 |
| org_level | INT | 组织层级 | 3 |
| parent_org_sk | INT | 上级组织代理键 | 3000 |
4.6 采购支出事实表设计
事实表是星型模型的核心,记录每笔采购支出的度量值,并通过外键关联四个维度表。
| 字段名 | 数据类型 | 说明 | 示例 |
|---|---|---|---|
| expense_sk | BIGINT | 事实表代理键,自增主键 | 5000001 |
| date_sk | INT | 日期维度外键 | 20250115 |
| supplier_sk | INT | 供应商维度外键 | 1001 |
| material_sk | INT | 物料维度外键 | 2001 |
| org_sk | INT | 采购组织维度外键 | 3001 |
| po_number | VARCHAR(20) | 采购订单号(退化维度) | PO-2025-00123 |
| quantity | DECIMAL(18,4) | 采购数量 | 10.5000 |
| unit_price | DECIMAL(18,4) | 单价(不含税) | 8500.0000 |
| total_amount | DECIMAL(18,2) | 总金额(不含税) | 89250.00 |
| tax_amount | DECIMAL(18,2) | 税额 | 11602.50 |
| total_with_tax | DECIMAL(18,2) | 含税总金额 | 100852.50 |
| currency | VARCHAR(3) | 币种 | CNY |
| exchange_rate | DECIMAL(18,6) | 汇率(兑本币) | 1.000000 |
4.7 星型模型SQL建表示例
-- 日期维度表
CREATE TABLE dim_date (
date_sk INT PRIMARY KEY,
full_date DATE NOT NULL,
year INT NOT NULL,
quarter INT NOT NULL,
month INT NOT NULL,
month_name VARCHAR(10),
week_of_year INT,
day_of_week INT,
is_weekend BOOLEAN,
is_holiday BOOLEAN DEFAULT FALSE
);
-- 供应商维度表
CREATE TABLE dim_supplier (
supplier_sk INT PRIMARY KEY,
supplier_code VARCHAR(20) NOT NULL,
supplier_name VARCHAR(100) NOT NULL,
region VARCHAR(50),
country VARCHAR(50),
supplier_tier VARCHAR(10),
risk_level VARCHAR(10),
payment_terms VARCHAR(50),
is_active BOOLEAN DEFAULT TRUE,
effective_date DATE NOT NULL,
expiry_date DATE NOT NULL DEFAULT '9999-12-31'
);
-- 物料维度表
CREATE TABLE dim_material (
material_sk INT PRIMARY KEY,
material_code VARCHAR(20) NOT NULL,
material_name VARCHAR(100) NOT NULL,
category_l1 VARCHAR(50),
category_l2 VARCHAR(50),
category_l3 VARCHAR(50),
unit VARCHAR(10),
specification VARCHAR(200),
is_procurable BOOLEAN DEFAULT TRUE
);
-- 采购组织维度表
CREATE TABLE dim_organization (
org_sk INT PRIMARY KEY,
org_code VARCHAR(20) NOT NULL,
org_name VARCHAR(100) NOT NULL,
company VARCHAR(50),
department VARCHAR(50),
cost_center VARCHAR(20),
region VARCHAR(50),
org_level INT,
parent_org_sk INT
);
-- 采购支出事实表
CREATE TABLE fact_purchase_expense (
expense_sk BIGINT PRIMARY KEY,
date_sk INT NOT NULL,
supplier_sk INT NOT NULL,
material_sk INT NOT NULL,
org_sk INT NOT NULL,
po_number VARCHAR(20),
quantity DECIMAL(18,4) NOT NULL,
unit_price DECIMAL(18,4) NOT NULL,
total_amount DECIMAL(18,2) NOT NULL,
tax_amount DECIMAL(18,2),
total_with_tax DECIMAL(18,2),
currency VARCHAR(3) DEFAULT 'CNY',
exchange_rate DECIMAL(18,6) DEFAULT 1.0,
FOREIGN KEY (date_sk) REFERENCES dim_date(date_sk),
FOREIGN KEY (supplier_sk) REFERENCES dim_supplier(supplier_sk),
FOREIGN KEY (material_sk) REFERENCES dim_material(material_sk),
FOREIGN KEY (org_sk) REFERENCES dim_organization(org_sk)
);
4.8 维度建模最佳实践与避坑指南
最佳实践:
- 代理键优先:始终使用自增代理键作为维度表主键,避免业务主键变更导致事实表关联断裂。
- 退化维度处理:采购订单号(po_number)直接保留在事实表中,不单独建维度表,减少关联复杂度。
- SCD策略选择:供应商名称、等级等属性使用Type 2;物料分类等稳定属性使用Type 0(固定);采购组织层级使用Type 1(覆盖)。
- 粒度定义:事实表粒度定义为"每笔采购订单行项目",确保每行记录对应一个物料在一个订单中的采购明细。
常见避坑:
- 不要在维度表中存储与维度无关的度量值(如供应商累计采购金额),这会破坏维度表的纯净性。
- 避免在事实表中存储可推导的冗余字段(如含税金额=不含税金额+税额),除非查询性能要求极高。
- 日期维度不要使用业务系统的日期表直接作为维度表,应构建独立的日期维度表并预填所有属性。
- 采购组织维度注意处理组织架构变更(如部门合并),建议使用SCD Type 2或桥接表处理多对多关系。
4.9 星型模型查询示例
以下SQL展示如何通过星型模型进行采购支出分析:
-- 查询2025年第一季度各供应商的采购总额
SELECT
ds.supplier_name,
ds.region,
SUM(fpe.total_amount) AS total_expense
FROM fact_purchase_expense fpe
JOIN dim_date dd ON fpe.date_sk = dd.date_sk
JOIN dim_supplier ds ON fpe.supplier_sk = ds.supplier_sk
WHERE dd.year = 2025
AND dd.quarter = 1
AND ds.is_active = TRUE
GROUP BY ds.supplier_name, ds.region
ORDER BY total_expense DESC;
-- 查询各物料类别在华东区的采购数量与金额
SELECT
dm.category_l1,
dm.category_l2,
SUM(fpe.quantity) AS total_qty,
SUM(fpe.total_amount) AS total_amount
FROM fact_purchase_expense fpe
JOIN dim_material dm ON fpe.material_sk = dm.material_sk
JOIN dim_organization dor ON fpe.org_sk = dor.org_sk
WHERE dor.region = '华东'
GROUP BY dm.category_l1, dm.category_l2
ORDER BY total_amount DESC;
性能提示:在事实表的外键列上建立复合索引(如(date_sk, supplier_sk, material_sk)),可大幅提升多维度组合查询的性能。对于超大规模数据,考虑按日期分区表。