Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions skills/data-warehouse-modeling/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
---
name: data-warehouse-modeling
description: >
数仓建模实战方法论——覆盖互联网和传统行业,侧重数字化转型企业的建模策略。
Use when: (1) 数仓分层设计 (2) 维度建模 (3) 指标体系 (4) 主题域划分
(5) 命名规范 (6) 建模评审 (7) 选方法论 (8) 湖仓一体 (9) 实时数仓
(10) SCD 处理 (11) 反模式排查 (12) dbt 工程化 (13) 云平台
(14) 数据治理 (15) 行业数仓——制造/医疗/政务/能源/农业/零售
(16) IoT 时序数据 (17) 非结构化数据 (18) OT/IT 融合
(19) 数字化转型各阶段数仓策略 (20) 传统企业渐进式建设。
用户说"建张表""指标怎么定义""传统企业怎么建数仓"时触发。
---

# 数仓建模

## 核心约束

**1. 数据单向流动,允许受控快捷路径**
- 标准层:ODS → DWD → DWS → ADS
- ADS 偶尔读 DWD 可以,必须注释原因,不能成常态
- 禁止 ADS 直接读 ODS

**2. 公共计算只做一次——"公共"标准是复用次数**
- 3 个以上下游消费 → 必须下沉到 DWS
- 1-2 个下游 → 允许在 ADS 各自计算,标注口径责任人
- 新建公共指标前提:已存在至少 2 个重复实现

**3. 每张事实表必须声明粒度**
- 写在 DDL 上方的 block comment 里,"一行代表什么"
- 混合粒度是事实表设计中最常见的致命错误
- 拿不准粒度时选最细

**4. 原子指标口径唯一**
- 先搞定口径共识再动手写 SQL
- 口径分歧是组织问题,不是技术问题

**5. 维度统一,不必一步到位**
- 先统一核心维度(用户/商品/时间/地域)
- 一致性维度建设进度 = 跨域分析能走多远

**6. 命名规范是新人的加速器**
- 目标:新来的人 3 天内看懂表结构
- 词根词典减少沟通成本

## 方法论选择——三层次决策

不要从"哪个方法论最好"出发。按这个顺序决策:

### 第一层:企业数字化成熟度

先问两个问题:"同一个客户在几个系统里有不同 ID?"、"数据团队多少人?"

| 转型阶段 | 特征 | 能做的 | 别碰的 |
|---------|------|--------|--------|
| 初始级(Excel 驱动) | 数据靠手工,无统一系统 | ODS + 1-2 张核心报表,星型模型最小集 | Data Vault、六层架构、实时数仓 |
| 部门级(系统烟囱) | ERP/CRM 独立,主数据不统一 | Kimball 星型 + DIM 层统一主数据 | Data Mesh、全量 Lakehouse |
| 企业级(跨系统打通) | 核心系统互联,开始建数据中台 | Data Vault + Kimball 混合、ELT | — |
| 数据驱动(智能化) | 数据是产品,AI 决策日常化 | Data Mesh、Lakehouse、批流一体 | — |

### 第二层:行业特性

→ 详细见 `references/industry-patterns.md`

| 行业 | 推荐方法论 | 核心原因 |
|------|-----------|---------|
| 互联网/电商 | Kimball 星型 | 已很成熟 |
| 制造业 | Data Vault + Kimball | 多源整合,IoT 进湖 + Kimball 出报表 |
| 医疗 | Inmon 3NF + Kimball mart | 临床数据关系复杂 |
| 政务 | MDM + 主题库 | 核心是跨部门共享,不是分析 |
| 能源/电力 | Data Vault + Lakehouse | 海量时序数据 |
| 农业 | Kimball + TSDB | 传感器 + 经营分析双轨 |

### 第三层:团队规模

| 团队规模 | 能做 | 别碰 |
|---------|------|------|
| 1-3 人 | ODS → ADS 三层,星型模型 | Data Vault(维护成本扛不住) |
| 3-5 人 | Kimball 四层,指标体系 | Inmon(工期太长) |
| 5-10 人 | Kimball + 部分论据库 | Data Mesh |
| 10+ 人 | Data Vault + Kimball 混合 | — |

## 渐进式建设策略

传统企业数仓一次建完的,从众没有见过成功的。按三步走:

```
第一步(1-3 个月):最小可行数据产品
选一个业务方每天用的报表,打通 1-2 个系统,只建 ODS → ADS 三层
→ 3 个月内出第一个可信数字,项目才能活下来

第二步(3-12 个月):主题域批量覆盖
财务 → 客户 → 供应链 → 人力
→ 这个阶段建 DIM 层和 DWS 层,命名规范和词根词典必须锁定

第三步(12 月+):智能化
批流一体、Lakehouse、ML Pipeline
→ 前提是第二步的数据治理已经到位
```

**第一步选场景的标准:** 数据源 ≤ 3 个系统;查询频次高(天天用所以价值感知强);计算逻辑简单(不容易出错)。财务日报是最安全的第一个场景。

## 分层架构

| 模式 | 分层 | 来源 | 适合谁 |
|------|------|------|-------|
| 国内标准 | ODS → DWD → DWS → ADS (+DIM) | 阿里 OneData | 互联网、制造业、能源 |
| Medallion | Bronze → Silver → Gold | Databricks | 湖仓一体 |
| dbt | sources → staging → marts | dbt Labs | 现代数据栈 |
| Data Vault | Raw Vault → Business Vault → Info Marts | Dan Linstedt | 金融、医疗、多源整合 |
| 政务标准 | ADR → ODS → DWD → DWS → ADS | 政务数据治理 | 政务 |

**转型期最小分层:** 只建 ODS → DW(合并 DWD+DWS)→ ADS 三层。DIM 在第二阶段加。

## 转型期特有的数据建模决策

**主数据不一致(MDM):** 不要试图一步到位消灭所有不一致。Registry(对照表,1-3 月)→ Consolidation(Golden Record,3-12 月)→ Coexistence(双向同步,12 月+)。

**纸电鸿沟:** 加 `source_type` 字段区分数据来源(手工/自动/传感器),`data_quality` 标记可信度。低质量数据不进核心指标。

**遗留系统:** CDC → Staging 层 1:1 镜像 → DWD 层再清洗。

## 维度建模要点

Kimball 四步法的核心是步骤顺序——先选业务过程,再选维度。搞反了就是灾难。

**粒度声明必须具体到 SQL 能写出来。** "订单粒度"不够——写清楚"每笔订单中的每个商品行"。

**事实表选择:**
- 事务事实表:记录事件发生。适合大多数场景
- 累积快照表:一条记录贯穿全流程。适合生产工单、维修工单
- 周期快照表:每天/每小时拍状态快照。适合库存、设备状态

**SCD 选择:** SCD2 是历史追溯唯一正确答案。SCD3 教科书里有,实际项目几乎不用。

**转型期特别关注:** 维度属性标注数据来源。同一个用户的手机号,CRM 里一个、ERP 里另一个——在 dim 表里记录两个来源的值,定义合并规则(来源优先级)。

## 指标体系

```
原子指标 = 业务过程 + 度量
派生指标 = 原子指标 + 业务限定 + 时间窗口 + 统计粒度
```

原子指标口径对齐是数据治理最难的环节。业务方说"GMV"至少要追问三个问题:含不含退款?含不含优惠?统计截止时间点?写进指标定义文档。

## 传统行业特有的数据格式

| 数据类型 | 处理的行业 | 处理策略 |
|---------|-----------|---------|
| 时序数据 | 制造/能源/农业 | TSDB + 数仓分层聚合,原始流不进 Hive |
| 空间数据(GIS) | 政务/零售/农业 | 维度表加 GIS 列 |
| 图数据 | 政务/供应链 | DWD 用点-边表,可引入图库 |
| 非结构化 | 医疗(影像)/政务(文档) | 数仓存元数据 + 路径,AI 提取标签 |
| 层级递归 | 制造(BOM)/所有 | 桥接表预计算,别用递归 CTE |

## 参考文件索引

| 文件 | 内容 |
|------|------|
| `references/methodology-comparison.md` | 四种方法论详细对比、决策树、混合架构 |
| `references/industry-patterns.md` | 行业建模 + 转型阶段 + 渐进式建设策略 |
| `references/layer-architecture.md` | 各层职责、五架构对比 |
| `references/subject-domains.md` | 12 个主题域 |
| `references/bus-matrix.md` | 总线矩阵设计、维度 DDL |
| `references/naming-conventions.md` | 表/字段命名、词根词典、数据类型 |
| `scripts/sql-templates.md` | 各层 DDL/DML(Hive/Spark) |
| `references/realtime-dw-design.md` | Kafka+Flink+OLAP |
| `references/antipatterns.md` | 反模式 P0/P1/P2 |
| `references/dbt-practices.md` | dbt 工程化 |
| `references/cloud-platform-practices.md` | Snowflake/BigQuery/Databricks/Redshift |
| `references/data-governance.md` | GDPR、CCPA、数据分级 |
| `references/dw-doc-standards.md` | 文档模板、评审清单 |

## 建模工作流

```
1. 业务调研 → 先判断数字化阶段,再画数据全景图(哪些系统有数据、什么格式、谁负责)
2. 架构设计 → 按阶段 + 行业 + 团队选方法论,选一个速赢场景验证
3. 规范定义 → 词根词典、命名规范、指标口径(这一步最容易被跳过)
4. 模型设计 → ODS 镜像 → DWD 粒度 → DWS 汇总 → ADS 服务
5. 评审 → 粒度、跨层、主键、口径、命名
6. 上线运维 → 质量监控、血缘、SLA
```

转型期最重要的原则:**先让数据跑起来,再让数据变完美。** 三个月不出第一个可信数字,项目大概率会死。
82 changes: 82 additions & 0 deletions skills/data-warehouse-modeling/references/antipatterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# 建模反模式

## P0 — 必须立即修复

### AP-01:事实表混合粒度
不同粒度数据混在一张表里,聚合结果必然出错。

### AP-02:ADS 直接读 ODS
绕过所有清洗和质量保障。

### AP-03:指标口径分裂
同一指标在多个表各算各的。三个报表三个数。

### AP-04:事实表无主键
重跑 ETL 后数据翻倍,没人发现。

### AP-05:源数据不做 Profile 就直接建模
**传统行业特有的高危反模式。** 制造业/医疗/政务的数据源比电商脏得多——同一个"客户名称"在三个系统里可能是三个值、字段类型不一致、关键字段缺失率 30%。不做 Data Profiling 就开始建模,后期重构成本是建模的数倍。

**修复:** ODS 接入后,先跑 Profile 脚本(字段缺失率、值分布、异常值),把问题清单过一遍再动手写 DDL。

## P1 — 短期内必须处理

### AP-06:数据烟囱
相同逻辑在多个表重复实现。迟早不一致。

### AP-07:ODS 层做了业务逻辑
丧失数据可追溯性。出问题没法跟源系统对账。

### AP-08:SCD 没处理
历史分析失真。

### AP-09:万能宽表
500+ 字段,没人敢改,新人看不懂。

### AP-10:维度碎片化
两个团队各维护一份 dim_user,跨域分析无望。

### AP-11:SELECT *
源系统改字段就大面积报错。

### AP-12:用递归 CTE 处理层级数据
**制造业特有错误。** BOM 配方、组织架构、设备树——这些层级结构用递归 CTE 在大数据量下性能极差。用预计算的桥接表代替递归查询。

### AP-13:时序数据直接入 Hive
**制造业/能源/农业特有错误。** 把秒级传感器数据直接导入 Hive 后按天分区——小文件问题、查询慢、分区开销大于查询本身。用 TSDB 存原始数据,Hive 只存聚合结果。

### AP-14:先把合规当"以后再加"
**医疗/政务/金融特有错误。** 等模型建好了再加脱敏、审计、分类分级——结果整个数仓要重构。合规要求必须在 ODS 层就开始落地。

## P2 — 建议优化

### AP-15:NULL 语义不明
"没折扣"用 0,"数据缺失"用 NULL。

### AP-16:分区粒度过细
10 万个小文件比查询本身还慢。

### AP-17:过深的 JOIN 链
7 层 JOIN 才能出报表。DWD 做维度退化。

### AP-18:维度表没有代理键
业务键变更时所有事实表都要更新。

### AP-19:缺少增量策略
百亿级事实表每次全量重算。

### AP-20:无数据质量监控
质量问题被下游发现,不是数据团队。

### AP-21:缺乏跨域沟通
**传统行业特有。** 制造业里 OT(操作技术)团队和 IT(信息技术)团队各说各话,数仓设计时只跟 IT 沟通忽略了 OT——结果上线后发现设备数据结构和预想的完全不一样。建模前必须拉上 OT 和 IT 两方一起画数据全景图。

## 排查优先级

按顺序排查:
1. 主键是否唯一(AP-04)— 不唯一 = 数据不可信
2. 粒度是否一致(AP-01)— 不一致 = 聚合一定错
3. 有没有跨层引用(AP-02)— 有 = 质量没保障
4. 指标口径是否统一(AP-03)— 不统一 = 数字打架
5. **源数据是否做过 Profile(AP-05)**— 没做 = 后续全是补丁
6. 剩下的按 P1 → P2 逐步清理
92 changes: 92 additions & 0 deletions skills/data-warehouse-modeling/references/bus-matrix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# 总线矩阵

## 为什么需要总线矩阵

总线矩阵解决一个核心问题:**哪些业务过程共用哪些维度。**

没有总线矩阵,每个团队各建各的维度表,`dim_user` 在交易域和流量域是两张表,跨域分析做不了。有了总线矩阵,所有共用的维度一目了然,公共维度层就知道该建哪些表。

## 怎么画

### Step 1:列业务过程
把主题域内的原子业务动作列出来。电商交易域:浏览、加购、下单、支付、退款。

### Step 2:列维度
把所有业务过程可能用到的分析角度列出来。用户、商品、时间、地域、渠道、促销。

### Step 3:填矩阵
每个交叉点标上 ●(使用)或留空(不使用)。

```
│ 用户 │ 商品 │ 时间 │ 地域 │ 渠道 │ 促销 │
───────────┼──────┼──────┼──────┼──────┼──────┼──────┤
商品浏览 │ ● │ ● │ ● │ ● │ ● │ │
加购 │ ● │ ● │ ● │ │ ● │ │
下单 │ ● │ ● │ ● │ ● │ ● │ ● │
支付 │ ● │ ● │ ● │ ● │ ● │ ● │
退款 │ ● │ ● │ ● │ │ ● │ │
```

### Step 4:识别一致性维度
出现 ● 超过 3 次的维度,必须建为公共维度(`dim_` 表)。

## 矩阵和 DWS 层的关系

矩阵中的每个 ● 交叉点,对应 DWS 层可能需要的一张汇总表。

```
业务过程:支付成功 × 维度:用户 + 商品 + 日期
→ dws_trade_pay_user_item_1d
```

但不是每个交叉点都要建表。只建下游确实在消费的。

## 维度表 DDL 示例

### dim_user(SCD2 拉链表)

```sql
-- 维度表必须用代理键做主键
CREATE TABLE dim_user (
user_sk BIGINT COMMENT '代理键(数仓自增)',
user_id BIGINT COMMENT '业务键(源系统)',
user_name STRING COMMENT '用户名',
phone_masked STRING COMMENT '手机号(脱敏后)',
gender STRING COMMENT '性别',
age_group STRING COMMENT '年龄段',
user_level STRING COMMENT '用户等级',
province_code STRING COMMENT '省份编码',
city_code STRING COMMENT '城市编码',
start_dt DATE COMMENT '生效日期',
end_dt DATE COMMENT '失效日期(9999-12-31 = 当前有效)',
is_current TINYINT COMMENT '当前行:1 是 0 否',
etl_dt DATE COMMENT 'ETL 日期'
) COMMENT '用户维度(SCD2 拉链表)'
PARTITIONED BY (dt STRING);
```

### dim_date(静态预生成)

```sql
-- 时间维度不需要 SCD,预生成 10 年的数据
CREATE TABLE dim_date (
date_key INT COMMENT 'YYYYMMDD',
full_date DATE COMMENT '完整日期',
year INT,
quarter INT,
month INT,
week_of_year INT,
day_of_week INT COMMENT '1=周一',
is_weekend TINYINT,
is_holiday TINYINT COMMENT '法定节假日',
holiday_name STRING,
fiscal_year INT COMMENT '财年',
fiscal_quarter INT
) COMMENT '时间维度(预生成 10 年)';
```

## 常见错误

1. **维度列太多** — 列 30 个维度没用。只列核心的(5-8 个),业务特有维度在子域级别管理
2. **业务过程粒度太粗** — "交易"不是业务过程,"下单"才是
3. **画完就完了** — 总线矩阵是活文档,业务新增过程时要更新
Loading