DD 数据开发学习站DATA ENGINEERING
模块 08 · 平台与数据服务

云数据仓库

存储计算分离、外部表、分区目录、按扫描量计费与成本控制。

难度 · 进阶 约 100 分钟 选学 练习 8 项 计划内 刷题 0/3
建议先学:容器化部署
本页目录 · 24 节

本章目标:能说清云数仓的存储计算分离架构,会用外部表和分区目录组织数据,并能估算一次查询的扫描成本和优化方向。 前置知识:数仓分层、OLAP 查询调优 预计用时:100 分钟

本地装一台数据库,数据量和并发一上来就撑不住;自己买服务器搭集群,又要提前预估容量,闲时资源浪费、忙时不够用。云数据仓库把存储和计算拆开卖,按实际用量付费,这是近几年数仓建设的主流形态。

1. 为什么需要云数据仓库

传统自建数仓有三个固定成本:

  • 容量要提前买:为年底大促准备 20 台机器,平时大部分时间闲着。
  • 扩容周期长:采购、上架、装环境,业务等不起。
  • 存储和计算绑死:数据存三年,但只有月初跑报表时才算,磁盘一直占着钱。

云数仓的解法是把两层分开:

        计算层(按需拉起、按秒/按量计费)
     ┌──────────┬──────────┬──────────┐
     │ 虚拟集群 A │ 虚拟集群 B │ 虚拟集群 C │
     └────┬─────┴────┬─────┴────┬─────┘
          │          │          │
     ┌────▼──────────▼──────────▼─────┐
     │      对象存储(S3 / OSS / COS)   │
     │      数据只存一份,长期保留        │
     └─────────────────────────────────┘

数据放在对象存储里只有一份,计算集群可以随时扩缩。多个部门还能各自拉起集群,共享同一份数据,互不抢资源。

2. 核心概念

2.1 存储计算分离

层 存什么 怎么计费 特点
存储层 表文件、Parquet、日志 按 GB/月 便宜、持久、可无限扩
计算层 内存、临时文件、执行计划 按秒/按扫描量/按节点时 弹性、可随时关停
元数据层 库表结构、分区、权限 通常很便宜 统一管理多个计算集群

分离之后,关掉计算集群不丢数据,也不影响别人查询。代价是计算读数据要跨网络,延迟比本地磁盘高,所以云数仓会做缓存、预取和列裁剪。

2.2 外部表与内部表

  • 内部表(Managed Table):数据由数仓管理,删表时数据一起删。
  • 外部表(External Table):数据在对象存储的某个路径,表只记录路径和格式,删表不删数据。

外部表特别适合数据湖:原始日志由采集程序写进对象存储,数仓只建一张外部表去读。多个引擎(Spark、Trino、数仓)可以读同一份文件。

2.3 按量付费与包年包月

计费方式 适合 风险
按扫描量 查询量波动大、临时分析 一条 SELECT * 可能扫掉几百 GB
按计算时长 固定时段的批处理 任务排队时也在计费
包年包月/预留 稳定高负载 预估过高会浪费

按扫描量计费时,优化 SQL 就是省钱。同一个结果,扫描 2 TB 和扫描 20 GB,账单差两个数量级。

2.4 主流产品对照

产品 存储 计算 常见场景
MaxCompute 阿里云盘古 按量/包年 国内离线数仓
EMR + Hive/Spark OSS/HDFS 按节点 自建 Hadoop 生态
Snowflake 云对象存储 虚拟仓库 海外多租户分析
BigQuery 列式存储 无服务器 按扫描量计费
Redshift 托管存储 集群 AWS 生态数仓
ClickHouse Cloud 对象存储 + 本地缓存 按节点 实时分析

产品名不同,核心模型一致:数据落在廉价存储,计算按需拉起,查询尽量少扫数据。

3. 动手示例

没有云账号也能验证这些概念。下面用 DuckDB 在本地模拟“对象存储 + 外部表 + 分区目录”。

3.1 把 CSV 当成外部表

CREATE OR REPLACE VIEW ext_orders AS
SELECT *
FROM read_csv_auto('data/sample/orders_demo.csv', header = true);

SELECT city, SUM(amount) AS gmv
FROM ext_orders
WHERE status = 'paid'
GROUP BY city
ORDER BY gmv DESC;

read_csv_auto 不导入数据,只按路径读取,行为类似外部表:文件还在原处,表只是访问入口。换成 read_parquet 就是云上更常见的列式格式。

3.2 按分区目录写 Parquet

云数仓通常用目录表达分区,例如 orders/dt=2024-01-01/part.parquet。DuckDB 可以直接生成这种布局:

COPY (
    SELECT
        *,
        CAST(order_date AS DATE) AS dt
    FROM read_csv_auto('data/sample/orders_demo.csv', header = true)
) TO 'data/lake/orders'
(FORMAT parquet, PARTITION_BY (dt), OVERWRITE_OR_IGNORE);

读取时开启 Hive 分区识别:

CREATE OR REPLACE VIEW lake_orders AS
SELECT *
FROM read_parquet(
    'data/lake/orders/**/*.parquet',
    hive_partitioning = true
);

SELECT dt, COUNT(*) AS rows, SUM(amount) AS gmv
FROM lake_orders
WHERE dt BETWEEN DATE '2024-01-01' AND DATE '2024-01-31'
GROUP BY dt
ORDER BY dt;

过滤 dt 时,引擎只打开匹配目录下的文件,其他月份的文件根本不会被读取。这就是分区裁剪。

3.3 估算扫描成本

假设某张表有 2 TB 数据,按扫描量计费,单价 0.03 元/GB:

查询写法 扫描量 费用
SELECT * 全表 2048 GB 61.44 元
只查 1 个月分区 约 171 GB 5.13 元
再只选 4 列(列存) 约 30 GB 0.90 元

计算公式:

费用 = 实际扫描 GB × 单价
实际扫描 = 总数据量 × 命中分区比例 × 命中列比例

注意“实际扫描”由引擎统计,不是文件总大小。压缩率高、列裁剪生效时,扫描量会明显小于磁盘占用。

3.4 生命周期管理

冷数据不必一直放在最贵的存储层。常见策略:

0–30 天   热数据,放标准存储,随时查询
31–180 天 温数据,转低频存储,查询频率下降
180 天以上 冷数据,转归档存储,查询前先解冻

对象存储一般支持生命周期规则,按前缀和天数自动转层或删除。数仓侧则按分区 DROP PARTITION 清理过期数据,避免元数据里堆着几万个空分区。

4. 常见坑

4.1 小文件太多

每批任务写几百个小文件,元数据操作和打开文件的开销超过读数据本身。按分区批量写、定期合并小文件,单文件控制在几十 MB 到几百 MB。

4.2 SELECT * 把账单打爆

列存只读需要的列。临时探索可以用 LIMIT 加采样,正式查询显式写列名。按扫描量计费的平台上,一条没加分区条件的查询可能直接产生一笔意外账单。

4.3 跨区域读数据

数据和计算在不同地域,每次扫描都走公网或跨区链路,慢且可能产生流量费。尽量让计算集群和存储桶在同一地域。

4.4 用外部表做高频点查

对象存储适合大范围扫描,不适合按主键查一行。高频点查应该进 KV/OLAP 数据库,而不是每次都去列文件。

4.5 忽略厂商锁定

各家的 SQL 方言、权限模型、存储格式都有差异。核心数据尽量用开放的 Parquet/ORC,元数据用统一 Catalog,降低迁移成本。

5. 在线练习

题目 考点
1193. 每月交易 I 按月聚合与状态统计
1321. 餐馆营业额变化增长 时间窗口与累计指标
1341. 电影评分 多条件排序取 TopN

自测:

  • 能说出存储计算分离后,关掉计算集群数据为什么还在。
  • 能解释分区裁剪和列裁剪分别减少了什么。

6. 面试延伸

面试题:什么是存储计算分离,解决了什么问题?

是什么:数据放对象存储,计算用独立集群按需拉起,两层分别扩缩和计费。

解决什么问题:存储和计算不再绑死,避免为峰值提前买机器;多团队共享一份数据,各自隔离计算资源。

我的实操边界:本章用 DuckDB 模拟外部表和分区目录,未开通云数仓账号做真实账单验证。

面试题:内部表和外部表怎么选?

是什么:内部表由数仓托管数据,外部表只登记对象存储路径。

解决什么问题:外部表让多个引擎共享同一份文件,删表不误删数据;内部表管理更省心,适合数仓自有的结果表。

我的实操边界:了解两者差异,未在生产环境配置外部表权限。

面试题:按扫描量计费时怎么控制成本?

是什么:分区裁剪、列裁剪、控制查询并发、限制 SELECT *、设置配额和预算告警。

解决什么问题:费用和扫描量直接挂钩,不规范的查询会放大账单。

我的实操边界:本章给出成本估算公式,未接入云厂商的预算系统。

面试题:小文件问题怎么产生、怎么处理?

是什么:频繁小批量写入产生大量小文件,读时打开和元数据开销大。用批量写、合并任务或写前攒批处理。

解决什么问题:文件数过多会让查询变慢,也会压垮元数据服务。

我的实操边界:了解合并思路,未处理过 TB 级小文件。

7. 本章验收

  • 能画出存储计算分离的架构,并说明每层怎么计费。
  • 能用 DuckDB 把 CSV 写成按日期分区的 Parquet,并读回验证。
  • 能写出带分区过滤的查询,并解释为什么其他分区不会被扫描。
  • 能根据总数据量、分区比例和列比例估算扫描量。
  • 能说出内部表和外部表各适合什么数据。
  • 能列出至少三条云数仓成本控制的措施。
本章任务0 / 8
本页目录