3. 数据仓库分层设计:ODS、DWD、DWS、ADS 各层职责与典型表结构设计原则

在采购支出数据仓库中,分层设计是保障数据可追溯性、降低ETL开发复杂度、提升查询性能的核心架构手段。每一层都有明确的职责边界和表结构约束,避免数据烟囱式开发。以下按照从源系统到最终应用的顺序,详细阐述各层职责与设计原则。

3.1 分层架构总览

采购支出数据仓库通常采用四层标准架构:ODS(操作数据存储层) → DWD(明细数据层) → DWS(汇总数据层) → ADS(应用数据层)。各层之间通过ETL任务单向流转,数据逐层收敛、聚合与主题化。

采购支出数据仓库四层架构 ODS 操作数据存储层 源系统近源复制 DWD 明细数据层 清洗·标准化·退化维度 DWS 汇总数据层 主题宽表·轻度汇总 ADS 应用数据层 报表·仪表板·接口 数据流向原则 单向流转,不跨层回写 每层只依赖下层数据 ETL调度顺序 ODS → DWD → DWS → ADS(串行依赖)
设计要点:ODS 层保持与源系统结构一致,不做业务清洗;DWD 层开始进行数据标准化与质量清洗;DWS 层面向分析主题构建宽表;ADS 层直接服务前端应用,允许适度冗余以换取查询性能。

3.2 ODS 层:操作数据存储层

核心职责:作为源系统数据的"近镜像"缓冲区,以最少的转换将采购业务系统的原始数据接入数据仓库。ODS 层不进行业务逻辑清洗,仅做必要的格式统一(如字符集转换、时间戳规范化)。

3.2.1 典型表结构设计原则

  • 字段级映射:表字段与源系统保持一一对应,字段名建议使用源系统原始字段名加前缀(如 src_)以标识来源。
  • 增量标识:必须包含 ods_batch_id(批次号)、ods_load_time(加载时间戳)、ods_operation_flag(I/U/D 操作标识)三个技术字段。
  • 分区策略:按日期分区(如 dt 字段),保留最近 30~90 天全量数据,历史数据归档至冷存储。
  • 禁止聚合:ODS 层不允许做任何汇总、去重或业务过滤,保留源系统最细粒度记录。

3.2.2 采购支出 ODS 层典型表清单

表名(逻辑)源系统主要字段分区键
ods_po_headerERP采购订单po_number, vendor_code, total_amount, create_datedt
ods_po_lineERP采购订单行po_number, line_num, material_code, quantity, unit_pricedt
ods_grnWMS收货单grn_number, po_number, receive_date, receive_qtydt
ods_invoice财务应付系统invoice_id, po_number, invoice_amount, tax_amountdt
ods_vendor_master供应商主数据vendor_code, vendor_name, payment_terms, risk_leveldt(全量快照)
常见误区:不要在 ODS 层做数据去重或空值填充。例如,采购订单行金额为空时,ODS 层应保留 NULL,由 DWD 层根据价格方差校验规则决定填充策略。ODS 层的"脏数据"是后续校验规则的原始输入。

3.3 DWD 层:明细数据层

核心职责:对 ODS 层数据进行清洗、标准化、维度退化与一致性处理,形成企业级一致的事实明细。DWD 层是数据仓库的"单一事实来源"(Single Source of Truth)。

3.3.1 典型表结构设计原则

  • 退化维度:将常用的维度属性(如供应商名称、物料类别、采购组织)直接退化到事实表中,减少关联查询。
  • 一致性度量:统一单位(如金额统一为人民币元、数量统一为基本计量单位)、统一货币汇率转换。
  • 清洗规则落地:在 ETL 过程中执行空值填充、异常值标记、格式校验,并记录清洗日志到 dwd_data_quality_log 表。
  • 缓慢变化维度(SCD)处理:对于供应商名称变更、付款条件调整等,采用 SCD Type 2 方式保留历史版本。

3.3.2 采购支出 DWD 层核心事实表设计

表名粒度关键度量字段退化维度字段
dwd_purchase_order_fact采购订单行order_qty, unit_price, line_amount, tax_amountvendor_name, material_category, org_name, currency_code
dwd_goods_receipt_fact收货单行receive_qty, receive_amount, quality_scorewarehouse_name, inspector_name
dwd_invoice_fact发票行invoice_amount, tax_amount, discount_amountvendor_name, payment_term_desc
dwd_price_variance_fact价格差异事件expected_price, actual_price, variance_amount, variance_ratematerial_name, vendor_name, variance_reason
-- DWD 层价格方差事实表 DDL 示例(PostgreSQL)
CREATE TABLE dwd_price_variance_fact (
    variance_id          BIGINT PRIMARY KEY,
    po_number            VARCHAR(20) NOT NULL,
    line_num             INT NOT NULL,
    material_code        VARCHAR(30) NOT NULL,
    material_name        VARCHAR(200),          -- 退化维度
    vendor_code          VARCHAR(20) NOT NULL,
    vendor_name          VARCHAR(200),          -- 退化维度
    expected_unit_price  DECIMAL(18,4),
    actual_unit_price    DECIMAL(18,4),
    variance_amount      DECIMAL(18,4),
    variance_rate        DECIMAL(8,4),
    variance_reason      VARCHAR(100),
    dwd_load_time        TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    dwd_batch_id         VARCHAR(50)
) PARTITION BY RANGE (dw_load_date);
价格方差校验规则在 DWD 层的落地:在 DWD 层 ETL 中,将采购订单单价与历史均价、标准成本、合同价进行对比,当偏差超过阈值(如 ±10%)时,生成价格方差事件记录到 dwd_price_variance_fact 表,并标记 variance_reason 字段(如"高于历史均价20%"、"低于合同价15%")。

3.4 DWS 层:汇总数据层

核心职责:基于 DWD 层明细数据,按分析主题构建轻度汇总宽表,减少重复计算,提升查询性能。DWS 层是数据仓库的"公共汇总层",面向跨主题分析。

3.4.1 典型表结构设计原则

  • 主题宽表:每个分析主题(如供应商分析、物料分析、采购组织分析)构建一张宽表,包含该主题下最常用的维度与度量。
  • 预聚合粒度:通常按"天 + 维度组合"进行聚合,如 dt + vendor_code + material_code。
  • 衍生指标:在 DWS 层计算同比、环比、累计值、移动平均等衍生指标,避免在报表层重复计算。
  • 数据冗余:允许适度冗余,将多个事实表的度量合并到一张宽表中,减少报表 JOIN 操作。

3.4.2 采购支出 DWS 层典型宽表

宽表名称粒度包含度量(示例)典型维度
dws_vendor_daily_agg供应商 + 天po_count, total_order_amt, total_receive_amt, total_invoice_amt, price_variance_count, avg_variance_ratevendor_code, vendor_name, risk_level, payment_terms
dws_material_daily_agg物料 + 天order_qty, receive_qty, avg_unit_price, price_std_dev, variance_flag_countmaterial_code, material_category, unit
dws_org_monthly_agg采购组织 + 月total_spend, budget_amount, spend_variance, vendor_count, top5_vendor_spendorg_code, org_name, region
-- DWS 供应商日汇总宽表 DDL 示例
CREATE TABLE dws_vendor_daily_agg (
    dt                  DATE NOT NULL,
    vendor_code         VARCHAR(20) NOT NULL,
    vendor_name         VARCHAR(200),
    risk_level          VARCHAR(10),
    po_count            INT DEFAULT 0,
    total_order_amt     DECIMAL(18,2) DEFAULT 0,
    total_receive_amt   DECIMAL(18,2) DEFAULT 0,
    total_invoice_amt   DECIMAL(18,2) DEFAULT 0,
    price_variance_count INT DEFAULT 0,
    avg_variance_rate   DECIMAL(8,4),
    dws_load_time       TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (dt, vendor_code)
) PARTITION BY RANGE (dt);
设计建议:DWS 层的汇总周期建议从"天"开始,后续根据查询频率扩展"周/月/季"汇总表。对于价格方差校验场景,price_variance_count 和 avg_variance_rate 是采购支出监控的核心指标,建议在 DWS 层预计算。

3.5 ADS 层:应用数据层

核心职责:直接面向报表工具、BI 仪表板、数据接口和临时查询。ADS 层的数据结构完全按消费端需求定制,不要求遵循星型或雪花型范式。

3.5.1 典型表结构设计原则

  • 需求驱动:每个 ADS 表对应一个具体的报表或接口需求,如"采购支出月度趋势报表"、"供应商价格方差排行榜"。
  • 宽表扁平化:将 DWS 层数据与维度属性合并为扁平宽表,减少报表 SQL 复杂度。
  • 预计算复杂指标:在 ADS 层完成排名、百分位、目标达成率等复杂计算。
  • 数据生命周期:ADS 层数据保留周期较短(通常 1~3 年),且支持快速重建。

3.5.2 采购支出 ADS 层典型表

表名服务对象数据来源刷新频率
ads_spend_trend_monthly采购支出趋势图dws_org_monthly_agg每日
ads_vendor_price_variance_top50价格方差排行榜dws_vendor_daily_agg每小时
ads_material_price_volatility物料价格波动分析dws_material_daily_agg每日
ads_budget_vs_actual预算执行仪表板dws_org_monthly_agg + 预算表每日
各层数据流转与典型表结构示例 ODS 层 ods_po_header ods_po_line ods_grn ods_invoice ods_vendor_master 清洗·标准化 DWD 层 dwd_purchase_order_fact dwd_goods_receipt_fact dwd_invoice_fact dwd_price_variance_fact dwd_data_quality_log 聚合·宽表 DWS 层 dws_vendor_daily_agg dws_material_daily_agg dws_org_monthly_agg dws_price_variance_agg 需求定制 ADS 层 ads_spend_trend_monthly ads_vendor_price_variance_top50 ads_budget_vs_actual
价格方差校验在 ADS 层的典型应用:通过 ads_vendor_price_variance_top50 表,采购分析人员可以直接查看价格偏差最大的前 50 个供应商,结合 variance_reason 字段快速定位异常采购订单,触发价格复审流程。该表每小时刷新,确保监控的实时性。

3.6 分层设计原则总结

分层核心原则数据粒度数据保留周期典型ETL频率
ODS近源复制,不做清洗源系统原始粒度30~90天实时/小时级
DWD清洗标准化,退化维度业务事件粒度1~3年小时级/天级
DWS主题宽表,预聚合天+维度组合1~3年天级
ADS需求驱动,扁平宽表报表/接口粒度1~3年小时级/天级
分层设计避坑指南:
  • ODS 层不要做业务清洗:一旦在 ODS 层过滤了"异常"数据,后续的价格方差校验将失去原始输入,无法发现源系统的问题。
  • DWD 层不要保留源系统字段名:必须统一为数据仓库标准命名,否则后续 DWS 和 ADS 层会陷入字段名混乱。
  • DWS 层不要做跨主题的复杂 JOIN:如果 DWS 层宽表需要关联 5 张以上 DWD 表,说明粒度设计不合理,应拆分为多个主题宽表。
  • ADS 层不要依赖 DWD 层直接查询:所有 ADS 表必须基于 DWS 层或 DWD 层汇总结果构建,避免报表 SQL 直接扫描明细数据。