4. 维度建模实战:采购日期维度、供应商维度、物料维度、采购组织维度的星型模型设计

在采购支出数据仓库中,星型模型是最常用的维度建模方法。它以事实表为中心,周围环绕多个维度表,形成星状结构。本章将围绕采购支出分析的核心需求,详细设计采购日期维度、供应商维度、物料维度和采购组织维度,并构建完整的星型模型。

4.1 星型模型总体架构

采购支出星型模型以采购支出事实表为中心,连接四个核心维度表。事实表存储可量化的采购指标(如金额、数量、单价),维度表提供描述性属性(如日期、供应商名称、物料分类)。

设计原则:
  • 事实表尽量轻量,只保留外键和度量值。
  • 维度表尽量宽表化,包含所有可能的分析属性。
  • 每个维度表有独立的代理键(Surrogate Key),与业务主键解耦。
采购支出星型模型架构 采购支出事实表 fact_purchase_expense date_sk (FK) supplier_sk (FK) material_sk (FK) org_sk (FK) 采购日期维度 dim_date date_sk (PK) full_date, year, quarter month, week, day_of_week 供应商维度 dim_supplier supplier_sk (PK) supplier_code, name region, tier, risk_level 物料维度 dim_material material_sk (PK) material_code, name category, unit, spec 采购组织维度 dim_organization org_sk (PK) org_code, org_name company, department 事实表通过代理键与四个维度表关联 每个维度表只与事实表直接连接,维度之间无直接关联

4.2 采购日期维度设计

日期维度是数据仓库中最通用的维度之一。在采购场景中,日期维度支持按年、季度、月、周、日进行采购趋势分析。

字段名数据类型说明示例
date_skINT代理键,自增主键20250101
full_dateDATE完整日期2025-01-15
yearINT年份2025
quarterINT季度(1-4)1
monthINT月份(1-12)1
month_nameVARCHAR(10)月份名称January
week_of_yearINT年内第几周3
day_of_weekINT周内第几天(1=周一)3
is_weekendBOOLEAN是否周末false
is_holidayBOOLEAN是否法定假日false
设计要点:日期维度建议一次性生成未来10年的数据,避免ETL运行时动态补录。代理键建议使用YYYYMMDD格式的整数,便于排序和分区。

4.3 供应商维度设计

供应商维度是采购分析的核心维度之一,支持供应商绩效评估、支出集中度分析、风险监控等场景。

字段名数据类型说明示例
supplier_skINT代理键,自增主键1001
supplier_codeVARCHAR(20)业务系统供应商编码SUP-00123
supplier_nameVARCHAR(100)供应商全称XX科技股份有限公司
regionVARCHAR(50)所属区域华东
countryVARCHAR(50)国家中国
supplier_tierVARCHAR(10)供应商等级(A/B/C)A
risk_levelVARCHAR(10)风险等级(高/中/低)低
payment_termsVARCHAR(50)付款条件Net 30
is_activeBOOLEAN是否启用true
effective_dateDATE生效日期2024-01-01
expiry_dateDATE失效日期9999-12-31
缓慢变化维度(SCD)处理:供应商维度通常采用SCD Type 2策略。当供应商名称、等级或风险级别发生变化时,生成新记录并更新生效/失效日期,保留历史快照。

4.4 物料维度设计

物料维度描述采购物料的属性,支持按物料类别、规格、单位等维度进行支出分析。

字段名数据类型说明示例
material_skINT代理键,自增主键2001
material_codeVARCHAR(20)物料编码MAT-04567
material_nameVARCHAR(100)物料名称不锈钢板 304 2mm
category_l1VARCHAR(50)一级分类原材料
category_l2VARCHAR(50)二级分类金属材料
category_l3VARCHAR(50)三级分类不锈钢板
unitVARCHAR(10)计量单位吨
specificationVARCHAR(200)规格描述304/2mm/1219x2438
is_procurableBOOLEAN是否可采购true

4.5 采购组织维度设计

采购组织维度描述企业内部采购管理架构,支持按公司、部门、采购组进行支出分摊分析。

字段名数据类型说明示例
org_skINT代理键,自增主键3001
org_codeVARCHAR(20)组织编码ORG-CN-SH
org_nameVARCHAR(100)组织名称上海采购中心
companyVARCHAR(50)所属公司XX集团中国有限公司
departmentVARCHAR(50)所属部门供应链管理部
cost_centerVARCHAR(20)成本中心编码CC-SH-001
regionVARCHAR(50)所属区域华东
org_levelINT组织层级3
parent_org_skINT上级组织代理键3000

4.6 采购支出事实表设计

事实表是星型模型的核心,记录每笔采购支出的度量值,并通过外键关联四个维度表。

字段名数据类型说明示例
expense_skBIGINT事实表代理键,自增主键5000001
date_skINT日期维度外键20250115
supplier_skINT供应商维度外键1001
material_skINT物料维度外键2001
org_skINT采购组织维度外键3001
po_numberVARCHAR(20)采购订单号(退化维度)PO-2025-00123
quantityDECIMAL(18,4)采购数量10.5000
unit_priceDECIMAL(18,4)单价(不含税)8500.0000
total_amountDECIMAL(18,2)总金额(不含税)89250.00
tax_amountDECIMAL(18,2)税额11602.50
total_with_taxDECIMAL(18,2)含税总金额100852.50
currencyVARCHAR(3)币种CNY
exchange_rateDECIMAL(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)),可大幅提升多维度组合查询的性能。对于超大规模数据,考虑按日期分区表。