数仓分层架构
概述
把数据仓库划分为 ODS、DWD、DWS、ADS、DIM 五层,是当前离线数仓的事实标准。分层解决三个问题:让数据流向清晰、让口径统一、让问题可回溯。本文逐层讲职责、数据流向与命名规范,并给出每层的落地示例。
一、为什么要分层
| 收益 | 说明 |
|---|---|
| 职责清晰 | 每层只做一件事,开发与排查定位明确 |
| 复用与共享 | DWS 汇总层一次建设,多张报表复用 |
| 口径统一 | 指标在 DWS 层统一定义,下游不再各自计算 |
| 容错与回溯 | 哪一层出问题,只重跑该层及其下游 |
不建层直接"贴源即用"的后果:每张报表各自 ETL,口径打架、重复计算、问题难定位。
二、分层总览
2.1 五层职责
| 层 | 全称 | 职责 | 典型表 |
|---|---|---|---|
| ODS | Operational Data Store | 贴源落地,原样接入 | ods_order |
| DWD | Data Warehouse Detail | 明细清洗、标准化、退化维度 | dwd_order_detail |
| DWS | Data Warehouse Summary | 按主题轻度汇总 | dws_user_daily |
| ADS | Application Data Store | 面向应用/报表的宽表与指标 | ads_gmv_daily |
| DIM | Dimension | 一致性维度主数据 | dim_user、dim_product |
2.2 数据流向
数据源(MySQL/Kafka/日志)
│
▼
ODS ──► DWD(清洗/标准化/维度退化)──► DWS(主题汇总)──► ADS(报表/接口)
│ ▲
└────► DIM(维度主数据)─────────────┘① 数据源 → ODS:原样入库,只做格式统一
② ODS → DWD:清洗脏数据、字段标准化、维度退化、宽表化
③ DWD → DWS:按主题(用户/订单/商品)轻度汇总成日快照
④ DWS → ADS:按报表/看板/接口需要生成指标宽表
⑤ DIM:贯穿全流程,各层 Join 维度的统一来源三、各层详解
3.1 ODS 层(贴源层)
| 要点 | 说明 |
|---|---|
| 目标 | 完整保留源数据,可回溯 |
| 粒度 | 与源系统一致,不做清洗 |
| 同步方式 | 全量快照 + 每日增量 |
| 分区 | 按日期分区 dt=20260815 |
| 存储 | 建议用 Hive/表格式(Hudi/Iceberg),保留原始结构 |
sql
CREATE TABLE ods_order (
order_id BIGINT,
user_id BIGINT,
product_id BIGINT,
amount DECIMAL(10,2),
create_time STRING
) PARTITIONED BY (dt STRING);3.2 DWD 层(明细层)
DWD 是数仓建模的核心层,做三件事:
| 处理 | 说明 | 示例 |
|---|---|---|
| 数据清洗 | 去重、去空、格式修正 | 电话号码脱敏、日期统一 yyyy-MM-dd |
| 维度退化 | 把冗余属性直接落到事实表 | 订单明细表直接带 user_name、city |
| 明细宽表 | 按业务过程组织成星型明细 | dwd_order_detail 一次性包含常用维度属性 |
sql
-- DWD:订单明细宽表(已退化维度)
CREATE TABLE dwd_order_detail (
order_id BIGINT,
user_id BIGINT,
user_name STRING,
city STRING,
product_id BIGINT,
product_name STRING,
category STRING,
amount DECIMAL(10,2),
quantity INT,
dt STRING
) PARTITIONED BY (dt STRING);3.3 DWS 层(汇总层)
按分析主题做轻度汇总,是"按天、按用户/商品"粒度的宽表:
| 主题 | 示例表 | 粒度 |
|---|---|---|
| 用户主题 | dws_user_daily | 用户 + 日期 |
| 商品主题 | dws_product_daily | 商品 + 日期 |
| 地区主题 | dws_area_daily | 城市 + 日期 |
sql
-- DWS:用户每日行为汇总
CREATE TABLE dws_user_daily (
user_id BIGINT,
dt STRING,
order_count INT,
order_amount DECIMAL(10,2),
login_count INT,
...
);DWS 层是口径收敛点:GMV、订单数等指标在这里唯一计算,下游 ADS 只做取值。
3.4 ADS 层(应用层)
面向报表、看板、数据接口的最终结果:
| 形式 | 示例 |
|---|---|
| 报表宽表 | ads_gmv_daily(日期 + GMV + 订单数) |
| 主题指标 | ads_user_retention_daily(留存率) |
| 服务接口表 | 供 BI/大屏直接查询 |
sql
-- ADS:每日 GMV 报表
CREATE TABLE ads_gmv_daily (
dt STRING,
gmv DECIMAL(10,2),
order_count BIGINT,
pay_amount DECIMAL(10,2)
);ADS 表通常物理删除(不再跨层复用),口径已固化。
3.5 DIM 层(维度层)
一致性维度的唯一来源:
| 维度 | 内容 |
|---|---|
dim_user | 用户主数据(含拉链表历史) |
dim_product | 商品主数据、品类层级 |
dim_date | 时间维度(日期、星期、节假日) |
DIM 采用 Inmon 式规范建模,各层 Join 都引用同一份 DIM,保证跨表口径一致。
四、命名规范
| 层 | 前缀 | 示例 |
|---|---|---|
| ODS | ods_ | ods_order |
| DWD | dwd_ | dwd_order_detail |
| DWS | dws_ | dws_user_daily |
| ADS | ads_ | ads_gmv_daily |
| DIM | dim_ | dim_user |
| 临时表 | tmp_ | tmp_xxx |
| 维度字典 | dwd_dic_ | dwd_dic_pay_type |
字段命名统一小写下划线,时间字段带 _time 后缀,金额字段带 _amount 后缀,日期统一 yyyy-MM-dd、时间戳统一 yyyy-MM-dd HH:mm:ss。
五、每层如何落地
| 层 | 技术选型建议 |
|---|---|
| ODS | Hive 分区表或 Hudi/Iceberg(近实时) |
| DWD/DWS | Hive/Spark SQL,按天分区批量计算 |
| ADS | Hive 输出后同步到 Doris/ClickHouse 供实时查询 |
| DIM | Hive 表 + 拉链表维护历史 |
| 调度 | DolphinScheduler/Airflow 编排层间依赖 |
实践提示:
- 层间依赖严格自上而下,禁止跨层读取(如 ADS 直接读 ODS)。
- 每一层的数据校验(行数、金额对账)放在层间调度节点上。
- 数据量小时可合并层(如 DWD 与 DWS 合并),量级大时保持严格分层。
六、常见问题
| 问题 | 处理 |
|---|---|
| ODS 数据重复 | 建表加主键/去重键,任务幂等重跑 |
| 层间口径不一致 | DWS 统一计算指标,禁止下游重算 |
| DWD 太宽 | 按业务过程拆表,宽表控制在常用字段内 |
| 回溯重跑成本高 | 按分区重跑 + 上游依赖链控制 |