CalcGuide · 技术博客主页 / 一页纸学习计划
🟠

数仓建模与 Lakehouse:从分层架构到表格式

分类:数据与人工智能 · 路径:docs/topics/warehouse-modeling-and-lakehouse/README.md

#data-warehouse#dimensional-modeling#lakehouse#iceberg#delta-lake

用分层架构 + 维度建模 + Iceberg/Delta/Hudi 表格式把数据湖升级为 Lakehouse

父主题

数据工程基础:从 ETL 到数仓与流处理

子主题(0)

数仓建模与 Lakehouse:从分层架构到表格式

0. 元信息

1. 学习路线

数仓分层架构 → 维度建模(星型 / SCD)→ 表格式概念 → Iceberg / Delta / Hudi 对比 → Time Travel → Lakehouse 落地

2. 阶段周数分配

阶段2 周方案2.5 周方案备注
1. 分层架构1.5 天2 天ODS / DWD / DWS / ADS / DIM
2. 维度建模2 天2.5 天事实表 + 维度表 + SCD Type 2
3. 表格式概念1.5 天2 天Parquet + Iceberg manifest
4. Iceberg / Delta / Hudi 对比1.5 天2 天三表格式写入基准
5. Time Travel1 天1.5 天写错 → 回滚 → 验证
6. Lakehouse 落地1.5 天2 天Iceberg on MinIO + Spark + Trino

每天 1.5~2 小时。2 周方案聚焦前 5 阶段;2.5 周方案多 2 天做 Lakehouse 端到端落地。

3. 核心知识 / 产出 / 标准表

阶段核心知识实践产出可观察学会标准
1. 分层架构ODS / DWD / DWS / ADS / DIM、命名规范、分区策略一份分层规范文档 + 完整 schema能讲清每层责任与命名边界
2. 维度建模事实表、维度表、星型 vs 雪花、SCD Type 1/2/3/4/6一份订单事实表 + 用户/商品/日期维度表能区分事实与维度并选 SCD 类型
3. 表格式概念Parquet / Avro / ORC、ACID、Snapshot、Time Travel、Schema Evolution一份 Iceberg 表的 schema 与 manifest 解读能讲清表格式与裸 Parquet 差异
4. Iceberg / Delta / Hudi 对比Spark 集成、Hive 集成、CDC、并发控制、性能一份对比表 + 3 个表的写入/读取基准能为不同场景选对表格式
5. Time Travel 与回滚Snapshot ID、Tag、Branch、回滚操作一份 Iceberg Time Travel 演练(写错 → 回滚 → 验证)能用 SQL 回到任意快照
6. Lakehouse 落地Catalog(Hive/Glue/Polaris)、SQL 引擎(Trino/Spark/Flink)一份 Docker Compose 起 Iceberg on MinIO + Spark + Trino能用 SQL 查询 Iceberg 表

4. 第一周(每天 1.5~2 小时)

Day 1 约定:本计划使用 Docker Compose 起 Iceberg on MinIO + Spark 3.5 + Trino。SQL 客户端用 spark-sqltrino。Iceberg 元数据用 SELECT * FROM table.files / table.snapshots / table.manifests 查。所有表必须可重跑:清空数据 + 重跑 DDL 产出相同 schema。

任务当天交付自检
Day 1装 Docker Compose + MinIO + Spark(iceberg-spark image)+ Trino;用 docker compose up -d 起服务;用 spark-sql 连 Iceberg catalogdocker-compose.yml + Iceberg catalog 配置spark-sql> CREATE DATABASE dw; 成功;SHOW DATABASESdwSELECT 1 跑通
Day 2建分层 ODS / DWD / DWS / ADS:写 CREATE TABLE DDL(4 张表),用命名规范 ods_ / dwd_ / dws_ / ads_ + 分区策略(PARTITIONED BY (days(order_date))4 张 Iceberg 表 DDL + 命名规范文档SHOW TABLES IN dw 列出 4 张表;DESCRIBE TABLE dw.ods_orders 显示分区字段;EXPLAIN 看是否走 partition pruning
Day 3维度建模:写 dwd_orders 事实表(订单 + 金额 + 时间)+ dim_user / dim_product 维度表;SCD Type 2 字段(effective_date / end_date / is_current3 张表 DDL + SCD Type 2 写入脚本INSERT INTO dim_user 含有效日期;UPDATE 旧版本时 end_date 被设;SELECT * FROM dim_user WHERE is_current=TRUE 只返回当前版
Day 4Iceberg Time Travel:写一个脚本故意 UPDATE 改错数据;用 SELECT * FROM dw.orders FOR SYSTEM_TIME AS OF '2026-01-15' 回看历史;用 CALL dw.system.rollback_to_snapshot('orders', snapshot_id) 回滚写错 + 回滚 + 验证脚本改错后 SELECT * FROM dw.orders 是错的;回滚后与改错前一致;SELECT snapshot_id, committed_at FROM dw.orders.snapshots 显示快照链
Day 5Iceberg / Delta / Hudi 对比:写 1 万行同一份数据到三种表格式;用 EXPLAIN ANALYZE 测写入耗时;用 SELECT count(*) FROM table.files 测小文件数三表格式对比表(写入耗时 / 小文件数 / 查询 P95)三种表都成功写入 1 万行;Iceberg 默认小文件最少;Hudi MOR 模式查询慢于 COW;Delta OPTIMIZE 后小文件合并
Day 6Catalog + 联邦查询:把 Iceberg 表挂到 Trino catalog;用 trino-cliSELECT * FROM iceberg.dw.dwd_orders;对比 Spark SQL 与 Trino 的查询计划Trino catalog 配置 + 查询计划对比Trino 查 Iceberg 跑通;EXPLAIN (FORMAT JSON) 看出 Trino 用 Iceberg 的 snapshot pruning;查询 P95 < 2s
Day 7步骤 A:跑通订单数仓最小链路(CSV → Iceberg ODS → dbt DWD/DWS/ADS);步骤 B:补齐 4 类边界(源文件缺失、分区冲突、Time Travel 失败、SCD Type 2 end_date 漏写)完整链路 + 故障演练报告pytest -k test_warehouse_idempotent 4 个用例全过;每类故障复现 + 防护措施写到 notes/week1-day7.md

Day 7 执行次序

步骤 A —— 最小可用数仓(60~90 分钟)

  1. 用 Spark 读 CSV → 写 Iceberg ods_orders
  2. dbt 写 dwd_orders(清洗 + SCD Type 2 关联维表);
  3. dbt 写 dws_orders_daily(按日汇总);
  4. dbt 写 ads_top_products(Top 10 商品);
  5. 4 层全部 dbt build 通过。

步骤 B —— 4 类边界用例(30~45 分钟)

#用例期望行为验证命令
B1CSV 文件缺失DAG 失败 + 告警pytest -k test_missing_csv
B2同一天重复写入行数不变(幂等)pytest -k test_idempotent
B3Time Travel 快照不存在报错并提示pytest -k test_bad_snapshot
B4SCD Type 2 漏 end_date测试失败 + 阻塞pytest -k test_scd_enddate

Day 7 当天必完成步骤 A;步骤 B 至少完成 B1、B2。

5. 阶段通用验收

  1. 不看答案独立重写一套 4 层 Iceberg 数仓 + Time Travel 演练;
  2. 用自己的话解释”为什么分层""为什么 SCD Type 2 常用""为什么 Iceberg 优于裸 Parquet""为什么 Hidden Partitioning 是关键”;
  3. 画一张图:分层架构图 + 维度模型星型图 + Iceberg manifest 关系图(三件套之一);
  4. 测试源缺失、分区冲突、Time Travel 失败、Schema 演进、小文件膨胀 5 类边界;
  5. 准备至少 3 组自定义数据集(电商 / IoT / 日志)并贴出实际 schema 与查询耗时;
  6. 记录 4 层每层行数、Iceberg 快照数、查询 P50 / P99、写入吞吐 4 个核心指标;
  7. 能修改已有 schema(加列 / 改类型 / 换分区策略)并用 Time Travel 验证历史可读。

交付存放:第 3 项的图、第 5 项的输出、第 6 项的指标,统一存到 week1/notes/week1/<table>/README.md

6. 最终验收

7. 综合项目

首选:mini Lakehouse(必做:分层数仓 + Iceberg + Time Travel + Trino 看板)。
备选:电商订单分析 Lakehouse(含 SCD Type 2 维表 + 维度建模 + Iceberg on MinIO)。
备选:IoT 时序 Lakehouse(含时序分区 + 流式写入 Iceberg + Grafana 看板)。

mini Lakehouse 必做要求:

任何综合项目都必须包含:

  1. 需求说明与数据契约(源 schema、目标 schema、SLA、分区策略);
  2. 分层架构图与命名规范文档;
  3. 核心代码(Spark SQL DDL + dbt models + Trino 看板配置);
  4. 边界测试(源缺失、分区冲突、Time Travel 失败、Schema 演进、小文件膨胀);
  5. 可观测(Iceberg snapshot 元数据 + Trino metrics);
  6. README(设计取舍、表格式选型理由、下一步);
  7. 复盘记录(模拟 1 次回滚 + 1 次 Schema 演进失败,写 retrospective.md);
  8. notes/ 规范
文件内容
notes/design.md分层架构图、维度模型星型图、命名规范
notes/test.md每组测试的输入 / 期望 / 实际 / 通过情况
notes/retrospective.md用时、难点、收获、改进点
notes/runbook.md常见失败 + 处置 SOP(回滚失败 / Schema 演进 / 小文件爆炸)
notes/iceberg-snapshots/Iceberg 快照与 manifest 截图(snapshots / manifests / files 视图)
notes/explain-output/关键 SQL 的 EXPLAIN ANALYZE 输出
notes/contract-yaml/数据契约(源 schema + 目标 schema + SLA + owner)
notes/sample-data/至少 3 组测试数据集(电商 / IoT / 日志) + schema 与耗时表

本主题贡献

数仓建模的核心矛盾是”分析查询要快 vs 业务需求会变”。本子主题专门讲清 star schema + Iceberg partition evolution 如何把这条矛盾变成可演进架构——以 Kimball star schema 为建模事实标准,dbt 为转换与测试引擎,Iceberg hidden partitioning + partition evolution 为存储演进基础,把 Time Travel 当作错误回滚与历史追溯的事实机制;不重复父主题的 Airflow 编排与通用 SQL 调优。

3 职责

  1. 用 star schema 把业务拆成”1 张事实表 + N 张维度表”,维度表配 SCD Type 2(effective_date / end_date / is_current)做历史追溯;事实表配 dbt 5 类测试(unique / not_null / relationships / freshness / accepted_values)做质量门禁。
  2. 用 Iceberg partition evolution(partition_spec 可演进,不重写历史数据)应对数据量变化——从按天分区演进到按月分区、按小时分区,下游查询自动走 partition pruning。
  3. 用 Iceberg Time Travel(SELECT * FROM tbl FOR SYSTEM_TIME AS OF 'snapshot-id' + CALL system.rollback_to_snapshot('tbl', snapshot_id))做错误回滚与历史审计;用 snapshots / manifests / files 元数据视图解读小文件与写入模式。

4 交付物

  1. 一份 4 层 Iceberg schema(ODS / DWD / DWS / ADS),事实表 fct_orders + 维度表 dim_user / dim_product / dim_date(SCD Type 2),命名规范 ods_ / dwd_ / dws_ / ads_ / dim_
  2. 一份 dbt 项目(staging / intermediate / marts 三层),5 条 dbt test,配 dbt source freshness + dbt build 质量门禁;Iceberg 表 PARTITIONED BY (days(order_date)) + TBLPROPERTIES ('format-version'='2')
  3. 一份 partition evolution 演练脚本(按天 → 按月 → 按小时三次演进),配 EXPLAIN 看 partition pruning 命中,每次演进后 Time Travel 读历史数据 OK。
  4. 一份 Iceberg 元数据解读报告(SELECT * FROM table.snapshots / manifests / files),含 Time Travel 回滚演练(写错 → rollback_to_snapshot → 验证一致)+ 三表格式对比基准(Iceberg / Delta / Hudi 写入耗时与小文件数)。

3 指标

  1. dbt build 5 类测试通过率 100%(dbt test 输出 5 passed,dbt build exit code 0)。
  2. Iceberg partition pruning 命中率 ≥ 90%(查询走分区裁剪,扫描文件数 / 总文件数 < 10%)。
  3. Time Travel 回滚恢复时长 < 1 min(rollback_to_snapshot 执行到下游查询一致)。

8. 推荐开源资料

阶段角色资料链接用法
全部主线书Ralph Kimball《The Data Warehouse Toolkit》https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/books/维度建模必读 1~5 章
全部对照书Bill Inmon《Building the Data Warehouse》https://www.wiley.com/en-us/Building+the+Data+Warehouse-p9780764599446CIF 建模对照读
1~2数仓Kimball Group Design Tipshttps://www.kimballgroup.com/category/design-tips/实战设计建议
3~4LakehouseApache Iceberg 官方文档https://iceberg.apache.org/docs/latest/表格式规范与 API
3~4LakehouseDelta Lake 官方文档https://docs.delta.io/与 Spark 深度集成
3~4LakehouseApache Hudi 官方文档https://hudi.apache.org/记录级索引与 CDC
5Time TravelIceberg Spec v2https://iceberg.apache.org/spec/快照与 manifest 规范
6联邦查询Trino 官方文档https://trino.io/docs/current/Iceberg connector
6存储MinIO 官方文档https://min.io/docs/minio/linux/index.htmlS3 兼容对象存储
6引擎Spark SQL 官方文档https://spark.apache.org/docs/latest/sql-programming-guide.htmlSpark 集成 Iceberg
全部哲学Kleppmann《DDIA》Ch.3 / 5https://dataintensive.net/存储与编码基础
全部生态对比Iceberg / Delta / Hudi 基准https://lakefs.io/blog/三种表格式性能对比博客

许可证提示:Iceberg / Delta / Hudi / Spark / Trino / MinIO 都是 Apache-2.0;Delta Lake 由 Linux Foundation 托管,商用无需特殊授权。复制 Apache 项目示例前请保留 LICENSE 与 NOTICE。默认做法是读规范后自己写 DDL,而不是复制官方 Example。

默认使用顺序:先读 Kimball《Toolkit》第 1~3 章建立维度建模心智 → 装 Iceberg on MinIO + Spark + Trino → 写 4 层 DDL → 用 SCD Type 2 写 dim_user → 跑 Time Travel 演练 → 对比 Iceberg / Delta / Hudi 写入基准 → 配 Trino catalog 做联邦查询 → 读 Iceberg Spec v2 看 manifest 规范 → 写复盘到 notes/retrospective.md

9. 学习资料汇聚(v0.3 自包含)

本节由本计划生成。链接指向原始材料或作者公开内容。规范会演进,记录时务必写明版本与日期。

9.1 背景与动机

传统数仓(Teradata、Greenplum、Snowflake)解决”结构化分析查询”问题,但成本高、扩展难。数据湖(HDFS + Parquet)解决”低成本存储任意数据”问题,但缺 ACID 与 schema。2017 年 Delta Lake、2018 年 Iceberg、2019 年 Hudi 先后开源,让 Lakehouse 把两者合一——同一份存储既支持低成本 schema-on-write 又支持 SQL 分析查询。Kimball 的维度建模理论从 1996 年至今仍是数仓建模的事实标准,星型 schema 与 SCD 仍是设计落点。

9.2 概念地图

flowchart LR
  Source[源系统] --> ODS[ODS 原始层]
  ODS --> DWD[DWD 明细层]
  DIM[维度表] --> DWD
  DWD --> DWS[DWS 汇总层]
  DWD --> DIM
  DWS --> ADS[ADS 应用层]
  Lake[Lakehouse Iceberg/Delta/Hudi] --> ODS
  Lake --> DWD
  Lake --> DWS
  Catalog[Hive/Glue/Polaris] --> Lake
  Engine[Spark/Trino/Flink] --> Lake

9.3 基础知识讲解

9.3.1 经典论文

资料贡献读法
Ralph Kimball, The Data Warehouse Toolkit(1996 初版)维度建模必读第 1~5 章
Bill Inmon, Building the Data Warehouse(1990)第三范式建模(CIF)与 Kimball 对照读
Armbrust et al., Delta Lake(VLDB 2020)Lakehouse 起点看 ACID 与 Time Travel
Schmidt et al., Apache Iceberg(2020)表格式规范看 manifest list
Kiran et al., Hudi(2021)记录级索引看 MOR vs COW

9.3.2 经典书籍

侧重用法
Ralph Kimball & Margy Ross, The Data Warehouse Toolkit(3rd ed., Wiley 2013)维度建模必读 1~5 章
Bill Inmon, Building the Data Warehouse(4th ed., Wiley 2005)CIF 建模选读 1~3 章
Holden Karau et al., Spark: The Definitive Guide(O’Reilly 2018)Spark 全景选读第 5 章(Spark SQL)

9.3.3 优秀博客与文档

资料特点用法
Apache Iceberg 官方文档表格式规范必读 spec + Spark 集成
Delta Lake 官方文档Delta 表 API看 Quickstart + Time Travel
Apache Hudi 官方文档Hudi 索引与 CDC看 COW vs MOR
Kimball Group维度建模方法看 Design Tips
Trino 官方文档联邦查询看 Iceberg connector

9.3.4 核心人物

人物影响材料
Ralph Kimball维度建模Kimball Group
Bill InmonCIF 建模DW 经典书
Michael ArmbrustDelta LakeSpark/Delta 公开演讲
Ryan BlueIceberg 起源Netflix 公开演讲
Vinoth ChandarHudi 起源Uber 公开演讲

9.3.5 开发方法

方法动作何时用
Layer-first先定分层规范,再写 schema任何数仓
Star-schema default星型优先,雪花慎用维度建模
SCD Type 2 for history历史追溯用 Type 2维度表
Hidden partitioning用 Iceberg/Hudi 自动分区写多读多
Partition evolution分区策略可演进数据量变化大

9.4 经典问题与经典案例(≥5 道)

#问题重要性最简答案
1ODS/DWD/DWS/ADS 四层怎么划分层基本原始 → 明细 → 汇总 → 应用
2星型 vs 雪花怎么选性能与可维护星型优先;维度过宽才雪花
3SCD Type 1/2/3 怎么选历史追溯大部分 Type 2
4Iceberg vs Delta vs Hudi表格式选型Spark 选 Delta,Hive 选 Iceberg,CDC 强选 Hudi
5Time Travel 怎么用错误回滚Iceberg 用 AS OF 子句
6Hidden Partitioning 怎么配性能partition_transform
7Schema 演进怎么兼容加列删列用表格式的 schema evolution
8Catalog 怎么选元数据管理Hive Metastore / AWS Glue / Polaris

9.5 学习难点

概念难点

难点突破路径
ODS 与 DWD 边界画一条订单从源到 ADS 的路径
SCD Type 2 实现写 effective_date / end_date
表格式 ACID 机制读 Iceberg manifest list

思维难点

难点突破路径
维度与事实区分用”可度量 vs 描述性”分类
表格式选型用三场景对比:批、CDC、读优化

工程难点

难点突破路径
Iceberg 并发写入冲突commit.retry.num-retries
Delta 小文件问题用 OPTIMIZE 合并
Hudi MOR 查询性能配 compaction 策略

9.6 技术标准与接口

Entity

名称版本组织状态许可证
Apache Iceberg1.xApacheGAApache-2.0
Delta Lake2.x / 3.xLinux FoundationGAApache-2.0
Apache Hudi0.14+ApacheGAApache-2.0
Apache Parquet2.xApache成熟Apache-2.0
Apache Avro1.11+Apache成熟Apache-2.0
Hive Metastore3.xApacheGAApache-2.0
AWS Glue CatalogAWS商业商业
Polaris Catalog0.xApache活跃Apache-2.0

Scope

Iceberg/Delta/Hudi 是表格式,不替代文件存储与计算引擎;Hive Metastore/Glue 是目录服务,不替代查询引擎。

Structure

Ecosystem

Depth Tiers

层级能力标准
L0知道存在知道数仓分层与 Lakehouse 概念
L1看得懂示例能读懂 Iceberg/Delta 表 schema
L2能正确调用能用 SQL/Spark 写入查询表格式
L3能解释与排错能定位并发冲突、Time Travel、Schema 演进问题
L4能设计与扩展能为新业务设计分层 schema + 表格式选型

本子主题目标:L3

Source

9.7 关键代码

9.7.1 Iceberg 表 + Time Travel

-- 9.7.1 Iceberg 表创建、写入、Time Travel
-- Spark SQL
CREATE TABLE dw.orders (
    order_id BIGINT,
    user_id BIGINT,
    amount DECIMAL(10, 2),
    order_date DATE
) USING iceberg
PARTITIONED BY (days(order_date))
TBLPROPERTIES ('format-version' = '2');

INSERT INTO dw.orders VALUES (1, 100, 99.50, DATE '2026-01-15');

-- Time Travel:回滚到上一个快照
CALL dw.system.rollback_to_snapshot('orders', <snapshot_id>);

-- 按快照时间查询
SELECT * FROM dw.orders FOR SYSTEM_TIME AS OF '2026-01-15 12:00:00';

9.7.2 SCD Type 2 维度表

-- 9.7.2 PostgreSQL 写 SCD Type 2 用户维度表
CREATE TABLE dim_user (
    user_id BIGINT,
    name TEXT,
    email TEXT,
    -- SCD Type 2 字段
    effective_date DATE NOT NULL,
    end_date DATE,
    is_current BOOLEAN NOT NULL DEFAULT TRUE,
    version INT NOT NULL DEFAULT 1
);

-- 一次性更新:触发新版本
UPDATE dim_user
SET end_date = CURRENT_DATE,
    is_current = FALSE
WHERE user_id = 100 AND is_current = TRUE;

INSERT INTO dim_user
VALUES (100, 'New Name', 'new@example.com', CURRENT_DATE, NULL, TRUE, 2);

9.7.3 Docker Compose 起 Iceberg on MinIO

# 9.7.3 docker-compose.yml:Iceberg on MinIO + Spark
services:
  minio:
    image: minio/minio:latest
    command: server /data --console-addess ":9001"
    environment:
      MINIO_ROOT_USER: minio
      MINIO_ROOT_PASSWORD: minio123
    ports: ["9000:9000", "9001:9001"]

  spark-iceberg:
    image: tabulario/iceberg-spark:3.5
    depends_on: [minio]
    environment:
      - AWS_ACCESS_KEY_ID=minio
      - AWS_SECRET_ACCESS_KEY=minio123
      - AWS_REGION=us-east-1
      - S3_ENDPOINT=http://minio:9000
    volumes: ["./warehouse:/warehouse"]

10. 常见误区

11. 所有知识点分类

  1. 编程语言
  2. 数据结构与算法
  3. 计算机基础
  4. 工程技术
  5. Web 与后端
  6. 前端与客户端
  7. 数据与人工智能
  8. 项目与职业能力
  9. 安全与可靠性

本计划归属:数据与人工智能 主 + 工程技术 辅。


直接依赖(2)

查看知识图谱