很多人第一次接触数据仓库时,最容易被一堆缩写劝退:ODS、DWD、DWS、ADS、DIM、STG、TMP、DM……看起来像一套黑话系统。
但这些缩写背后真正要解决的问题并不复杂:公司里的数据从业务系统、日志、埋点、消息队列流进来以后,不能所有人都直接查原始表,也不能每个报表都从头写一遍清洗和聚合逻辑。
所以数仓会把数据加工过程拆成不同层级。每一层负责一类事情:有的保存原始数据,有的做清洗和标准化,有的沉淀公共汇总,有的直接服务报表、看板和业务决策。
一、一句话总览
如果只用一句话解释这些概念,可以这样理解:
STG:在进入正式数仓前先接住和缓冲数据
ODS:把原始数据接进来,尽量保留现场
TMP:承接加工过程里的临时中间结果
DWD:把数据清洗成可信、可复用的明细事实
DIM:沉淀业务对象的维度信息
DWS:围绕主题和实体做公共汇总
ADS:面向具体应用、报表、看板和接口输出结果
它们串起来大概是这样:
业务系统 / 日志 / MQ / 第三方数据
↓
STG / ODS
↓
TMP(可选)
↓
DWD + DIM
↓
DWS
↓
ADS
↓
BI 看板 / 经营分析 / 风控策略 / 推荐特征 / API 服务
注意,数仓分层不是为了显得架构很复杂,而是为了让数据在流转过程中逐步变得可信、可复用、可追踪、可服务。
二、为什么需要数仓分层
假设公司只有一张订单业务库表,分析师想看城市维度 GMV,运营想看商家转化,风控想看异常下单,算法想做用户购买特征。如果所有人都直接查业务库或原始日志,很快会出现几个问题。
- 口径不一致:有人把退款订单算进 GMV,有人不算;有人按支付时间统计,有人按下单时间统计。
- 逻辑重复:每个报表都重复写订单状态过滤、时间分区、用户城市映射、商家类目 Join。
- 链路不可追踪:报表数字异常时,不知道问题出在采集、清洗、维表、汇总还是展示层。
- 性能不可控:临时分析和线上报表都扫明细大表,任务互相影响。
- 治理困难:字段含义、生命周期、负责人、数据质量和权限都散落在各处。
分层的价值就是把这些问题拆开:原始数据归原始层,公共清洗归明细层,通用汇总归汇总层,具体应用归应用层。这样一来,数据问题可以定位,指标口径可以复用,报表建设也不会每次从零开始。
三、ODS:原始数据层
ODS 通常叫 Operational Data Store,国内数仓里经常翻译成操作数据层、原始数据层、贴源层。
它的核心职责是:把业务系统、日志系统、消息队列、第三方接口里的数据接入数仓,并尽量保留原始形态。
比如订单业务库里有一张表:
mysql.order_info
- order_id
- user_id
- shop_id
- status
- pay_amount
- created_at
- updated_at
同步到数仓 ODS 后,可能会变成:
ods_trade_order_info_di
- order_id
- user_id
- shop_id
- status
- pay_amount
- created_at
- updated_at
- dt
这里的 di 常表示按天增量分区,dt 是分区字段。不同公司命名不完全一样,但语义类似:这张表接近源系统,主要用于保留当天同步来的原始订单数据。
ODS 层通常有几个特点:
- 字段尽量贴近源系统,不轻易改业务含义;
- 保留原始状态值、原始时间、原始主键;
- 可以做必要的格式修正、去重、分区补齐,但不做重业务口径加工;
- 主要服务下游加工和问题追溯,不直接服务复杂分析。
一句话:ODS 是数据进入数仓后的第一现场。
四、STG:临时接入和缓冲层
STG 通常是 Staging 的缩写,也叫暂存层、缓冲层。不是每个公司都会把 STG 单独作为正式分层,有些公司会把它并入 ODS。
STG 更偏技术缓冲,常见用途包括:
- 接收还没有完全校验的原始文件;
- 承接临时导入、历史回灌、一次性修复数据;
- 做格式转换前的落盘,例如 JSON、CSV、日志行暂存;
- 隔离外部系统波动,避免直接污染正式 ODS 表。
可以把 STG 理解成进入正式数仓前的卸货区。货先放在这里,检查包装、数量和格式,再进入 ODS 或 DWD。
五、TMP:临时加工层
TMP 通常是 Temporary 的缩写,也叫临时层、临时表层、临时加工层。它和 STG 都带一点「临时」的味道,但位置和职责不一样:STG 更像进入正式数仓前的接入缓冲,TMP 更像加工任务内部的中间草稿。
TMP 的核心职责是:把复杂加工过程中的中间结果临时落下来,方便拆分 SQL、复用本次任务结果、排查问题或承接一次性数据处理。
比如订单明细加工可能需要先把订单、支付、退款、优惠、配送等多张表拼到一起。如果一条 SQL 太长,或者中间结果需要反复校验,就可能先落一张临时表:
tmp_trade_order_pay_refund_di
- order_id
- user_id
- shop_id
- pay_amount
- refund_amount
- coupon_amount
- delivery_status
- dt
这张表的价值不是对外提供稳定口径,而是帮助当前加工任务把复杂逻辑拆开。任务跑完、回灌结束或问题排查完成后,它就应该被清理,或者至少有明确的保留周期。
TMP 层常见用途包括:
- 把很长的 SQL 拆成几步,降低开发和排障难度;
- 承接历史回灌、数据修复、一次性分析的中间结果;
- 在 DWD、DWS、ADS 加工过程中临时缓存 Join 或聚合结果;
- 保存校验样本、异常数据、重跑任务的阶段性结果。
TMP 最大的风险是「临时表长期化」。如果一张 TMP 表开始被多个下游长期依赖,它就不应该继续叫 TMP,而应该被重新建模,沉淀到 DWD、DWS 或 ADS。
一句话:TMP 是加工过程里的临时工作台,不是稳定的数据资产层。
六、DWD:明细事实层
DWD 通常叫 Data Warehouse Detail,也就是明细数据层。它是数仓里非常关键的一层。
DWD 的核心职责是:把 ODS 中贴源但不够好用的数据,清洗成业务含义清晰、粒度稳定、可复用的明细事实表。
比如 ODS 里订单状态可能很混乱:
status = 0 创建
status = 1 已支付
status = 2 已取消
status = 3 已退款
status = 9 测试订单
DWD 层会做标准化处理,例如:
- 过滤测试订单、脏数据、重复数据;
- 统一字段命名和字段类型;
- 补充业务可理解的状态枚举;
- 把订单、支付、退款、履约等事实拆成稳定主题;
- 保证一张事实表有明确粒度,比如一行代表一笔订单、一笔支付、一次曝光、一次点击。
一张 DWD 订单明细表可能是:
dwd_trade_order_detail_di
- order_id
- user_id
- shop_id
- city_id
- category_id
- order_status
- is_paid
- is_refund
- pay_amount
- order_time
- pay_time
- dt
这张表仍然是明细表,不是汇总表。它的重点不是提前算好报表指标,而是让下游可以基于可信明细继续加工。
一句话:DWD 是把原始数据变成标准业务事实。
七、DIM:维度层
DIM 是 Dimension 的缩写,也就是维度层。
事实表记录「发生了什么」,维度表解释「是谁、在哪、属于什么、当前是什么状态」。例如:
- 订单事实:一笔订单支付了 89 元;
- 用户维度:这个用户来自哪个城市、注册渠道是什么、会员等级是什么;
- 商家维度:这个商家属于哪个品类、所在商圈是什么、是否品牌商家;
- 商品维度:这个商品属于哪个类目、价格带是什么、是否新品。
常见维表命名类似:
dim_user_df
用户维度,全量快照表
dim_shop_df
商家维度,全量快照表
dim_item_category_df
商品类目维度,全量快照表
这里的 df 常表示按天全量快照。维度数据容易变化,例如用户等级会变、商家品类会调、城市归属会改,所以维表经常需要保留每日快照,甚至用拉链表记录历史版本。
DIM 层最容易被低估。没有好的维度层,DWD 明细表就很难被稳定解释,DWS 和 ADS 的口径也会漂。
八、DWS:公共汇总层
DWS 通常叫 Data Warehouse Summary,也就是汇总数据层、公共汇总层、主题汇总层。
DWS 的核心职责是:围绕稳定的业务主题、实体和时间周期,把 DWD 明细事实聚合成可复用的公共汇总数据。
比如很多下游都会用到这些数据:
- 用户近 1 天、7 天、30 天下单次数;
- 商家每天的订单数、支付金额、退款金额;
- 城市每天的访问人数、下单人数、支付转化率;
- 商品类目每天的曝光、点击、成交、GMV。
如果这些逻辑每个报表都单独算,就会重复、慢、不一致。DWS 会把它们沉淀成公共层。
dws_trade_user_1d_di
- user_id
- order_cnt_1d
- paid_order_cnt_1d
- pay_amount_1d
- refund_amount_1d
- dt
dws_trade_shop_1d_di
- shop_id
- order_cnt_1d
- pay_amount_1d
- refund_order_cnt_1d
- dt
DWS 的关键词是公共。它不应该只服务一个页面、一个临时分析或一个很窄的需求,而应该沉淀多个场景都能复用的主题汇总能力。
一句话:DWS 是把明细事实聚合成公共业务能力。
九、ADS:应用数据层
ADS 通常叫 Application Data Service,也叫应用层、数据服务层、应用数据层。
ADS 的核心职责是:面向具体应用场景组织最终数据形态。
比如经营看板需要一个城市经营日报,它关心的不是下游能否复用,而是页面需要什么字段、什么排序、什么口径、什么更新时间。
ads_city_business_dashboard_di
- city_id
- city_name
- gmv
- order_cnt
- pay_user_cnt
- new_user_cnt
- refund_rate
- conversion_rate
- target_finish_rate
- dt
ADS 层常见服务对象包括:
- BI 报表和可视化大屏;
- 经营分析日报、周报、月报;
- 业务系统里的数据接口;
- 风控策略、营销圈选、用户画像;
- 算法特征、实验分析和效果归因。
ADS 的特点是强场景、强交付、强时效。它可以依赖 DWS,也可以在必要时回到 DWD 取更细粒度数据,但不应该把大量重复清洗逻辑长期堆在 ADS 里。
一句话:ADS 是把数仓能力包装成业务能直接使用的数据产品。
十、用订单分析串起来看一遍
假设我们要做一个「城市经营看板」,展示每天每个城市的 GMV、订单数、支付用户数和退款率。
一条比较典型的数据链路是:
1. ODS
ods_trade_order_info_di
从订单库同步原始订单数据
2. TMP(可选)
tmp_trade_order_pay_refund_di
在复杂加工中临时拼接订单、支付、退款等中间结果
3. DWD
dwd_trade_order_detail_di
清洗测试订单、统一状态、明确一行一单
4. DIM
dim_city_df / dim_shop_df / dim_user_df
补充城市、商家、用户等解释信息
5. DWS
dws_trade_city_1d_di
按城市和日期汇总订单数、GMV、退款金额
6. ADS
ads_city_business_dashboard_di
拼出看板所需字段,补充目标达成率、同比环比、排序展示
同一个指标在不同层的形态不同。DWD 里是一笔笔订单,DWS 里是按城市和天聚合后的公共结果,ADS 里是经营看板直接使用的最终宽表。
十一、几层之间到底怎么区分
| 层级 | 核心问题 | 典型粒度 | 主要使用者 |
|---|---|---|---|
| STG | 数据先接住 | 文件、批次、原始记录 | 数据开发、同步任务 |
| ODS | 原始数据保留下来 | 接近源表或原始日志 | 数据开发、排障、下游加工 |
| TMP | 中间结果先落下 | 任务中间表、临时宽表、批次结果 | 数据开发、一次性分析 |
| DWD | 明细事实变可信 | 订单、支付、点击、曝光等事实明细 | 数据开发、分析师、算法工程 |
| DIM | 业务对象可解释 | 用户、商家、商品、城市等维度 | 所有下游 |
| DWS | 公共指标可复用 | 按主题、实体、时间窗口汇总 | 数据开发、分析师、应用层 |
| ADS | 业务场景能直接用 | 报表、接口、策略、特征所需形态 | 业务方、BI、产品、算法、服务接口 |
最关键的区分方法不是看表名,而是看它的责任边界:
- 如果主要为了保留源数据,是 ODS;
- 如果主要为了支撑某个加工任务的中间计算,是 TMP;
- 如果主要为了沉淀可信明细,是 DWD;
- 如果主要为了解释实体属性,是 DIM;
- 如果主要为了复用公共汇总,是 DWS;
- 如果主要为了服务具体应用,是 ADS。
十二、常见表命名怎么读
很多数仓表名会长成这样:
dwd_trade_order_detail_di
│ │ │ │ └─ 分区/更新方式:di 表示日增量
│ │ │ └──────── 粒度或形态:detail 明细
│ │ └────────────── 业务对象:order 订单
│ └──────────────────── 业务域:trade 交易
└──────────────────────── 层级:dwd 明细层
常见后缀大致可以这样理解,不同团队会有差异:
| 后缀 | 常见含义 | 例子 |
|---|---|---|
di | daily incremental,按天增量 | 当天新增或变更订单 |
df | daily full,按天全量快照 | 每日用户维度快照 |
1d | 最近 1 天或按天统计 | 用户日订单数 |
7d | 最近 7 天窗口统计 | 用户近 7 天点击数 |
td | 截至当天累计 | 本月至今累计 GMV |
命名不是越长越好,而是要让别人一眼看出:这张表在哪一层、属于哪个业务域、是什么对象、什么粒度、怎么分区。
十三、事实表和维度表
理解 DWD 和 DIM 时,经常会遇到两个词:事实表和维度表。
事实表记录业务事件,例如订单、支付、退款、曝光、点击、发货、签收。事实表里通常有可度量的指标字段,例如金额、数量、时长、次数,也有连接维度的 key,例如 user_id、shop_id、city_id。
维度表记录业务对象的属性,例如用户性别、城市名称、商家品类、商品品牌。维度表让事实可以被分析和解释。
事实:用户 1001 在 2026-06-16 支付了一笔 89 元订单
维度:用户 1001 是北京用户,商家属于快餐品类,城市属于华北大区
数仓里常说的「星型模型」就是一张事实表周围连接多张维度表。DWD 里沉淀可信事实,DIM 里沉淀稳定维度,DWS 再基于它们做公共汇总。
十四、DM:数据集市是什么
DM 通常指 Data Mart,也就是数据集市。它不是所有公司都会单独放在标准分层里,但在大型组织里很常见。
可以把数据集市理解成面向某个业务线、部门或主题域的小型数仓。例如:
- 营销数据集市;
- 风控数据集市;
- 用户增长数据集市;
- 履约配送数据集市。
它可能包含自己的 DWS 和 ADS,也可能只是从集团公共数仓中抽取一部分数据,做面向部门的二次组织。
如果公共数仓解决的是全公司统一口径,数据集市解决的就是某个业务方向的高频使用和快速交付。
十五、实时数仓里的这些层还存在吗
实时数仓里仍然会使用类似分层,只是计算引擎和数据形态变了。
Kafka 原始日志 → realtime_ods
Flink 清洗明细 → realtime_dwd
Flink 窗口聚合 → realtime_dws
Doris / ClickHouse → realtime_ads
实时链路更强调低延迟、乱序处理、状态管理、Exactly-once、维表 Join 和结果更新。它不像离线数仓那样天然按天批处理,所以层级边界有时会更薄。
但原则仍然相同:原始数据、可信明细、公共汇总、应用服务要尽量分清。否则实时链路也会陷入同样的问题:口径重复、逻辑散落、异常难排查。
十六、常见误区
数仓分层最常见的问题,不是大家不知道 ODS、DWD、DWS、ADS 这几个词,而是表名像分层,实际职责没有分清。
| 误区 | 问题 | 更好的做法 |
|---|---|---|
| ODS 里做太多清洗 | 原始现场丢失,排障困难 | ODS 尽量贴源,清洗放到 DWD |
| TMP 长期被下游依赖 | 临时表变成隐形公共层,血缘和口径失控 | 设置生命周期,复用稳定后沉淀到 DWD/DWS/ADS |
| DWD 做成汇总表 | 明细不可复用,下游难扩展 | DWD 保持稳定明细粒度 |
| DWS 只服务一个报表 | 公共层退化成应用层 | DWS 围绕主题沉淀可复用汇总 |
| ADS 堆满复杂清洗逻辑 | 口径散落,维护成本高 | 把公共逻辑下沉到 DWD/DWS |
| 维表没有历史版本 | 回看历史数据时口径漂移 | 用快照表或拉链表管理变化 |
| 只分层不治理 | 表很多但没人敢用 | 补齐负责人、血缘、质量、SLA、生命周期 |
十七、真正落地时怎么做
如果从零建设一个数仓,不应该先纠结表名前缀,而应该先回答几个问题。
- 业务域怎么划分:交易、用户、商家、商品、履约、营销、风控分别是什么边界?
- 核心事实有哪些:订单、支付、退款、曝光、点击、配送、核销分别是什么粒度?
- 核心维度有哪些:用户、商家、商品、城市、类目、渠道、活动如何管理?
- 公共指标有哪些:GMV、订单数、支付用户数、转化率、退款率的统一口径是什么?
- 服务场景有哪些:报表、API、策略、算法、实验分析分别需要什么数据形态?
- 治理机制是什么:谁负责、什么时候产出、质量怎么校验、失败怎么报警、历史保留多久?
分层只是骨架,真正让数仓变好用的是指标口径、数据质量、任务稳定性、元数据、血缘、权限和文档。
结语
ODS、DWD、DWS、ADS 这些缩写本身并不神秘。它们只是把数据从「原始」到「可用」再到「可服务」的过程拆成几个责任清晰的阶段。
STG 负责接入缓冲,ODS 保留现场,TMP 承接加工过程里的临时中间结果,DWD 沉淀可信明细,DIM 解释业务对象,DWS 提供公共汇总,ADS 面向具体应用交付结果。DM 等层则根据团队规模、数据复杂度和交付方式补充使用。
判断一张表应该放在哪一层,不要只看它叫什么,而要问:它是在接入缓冲、保留原始数据、支撑临时加工、清洗明细事实、解释维度属性、沉淀公共汇总,还是服务具体应用?
这就是数仓分层最重要的意义:让数据链路里的每一步都有明确责任,让同一份数据可以被更多人放心复用。