分区与分桶设计是什么
分区(partition)把表数据按目录切分,常见按日期 dt 做一级分区,必要时加二级(region、hour);分桶(bucket)按高基数列做哈希切分,用于提升连接效率与采样精度。分区解决「少读数据」,分桶解决「读得快、连得动」。前提是查询能命中分区条件——用函数包装分区字段的写法会让裁剪完全失效,分区设计等于白做。
基本信息
| 适用平台 | Apache Hive、Spark SQL、以及采用 Hive 目录结构的数仓引擎 |
|---|---|
| 分区字段 | 多为 STRING 类型(dt='2026-10-11'),也可用 INT |
| 分区层次 | 一级分区(dt)最常见,二级如 dt + region、dt + hour |
| 分桶 | CLUSTERED BY (user_id) INTO N BUCKETS,桶数常取 2 的幂 |
| 安装方式 | 静态指定分区,或动态分区一次写入多个分区 |
| 生命周期 | 按天归档与清理,控制分区总数与元数据规模 |
典型使用场景
- 增量表按天分区:每天一个分区,重跑时覆盖写单天分区即可
- 大表按月分区:历史久、查询以月为单位的表,减少分区数量
- 高基数列分桶:事实表按 user_id 分桶,与大表连接时可走桶连接
- 二级分区:地域或小时差异明显、查询常带该维度时使用
- 数据生命周期:按分区归档历史数据并在元数据中下线,控制存储成本
分区分桶建表与写入
分区分桶建表与写入
CREATE TABLE dwd_trade_order_detail_di (
order_id BIGINT, user_id BIGINT, pay_amount DECIMAL(18,2)
)
PARTITIONED BY (dt STRING)
CLUSTERED BY (user_id) INTO 64 BUCKETS
STORED AS ORC;
-- 指定分区写入:重跑同一天只覆盖该分区
INSERT OVERWRITE TABLE dwd_trade_order_detail_di PARTITION (dt = '2026-10-11')
SELECT order_id, user_id, pay_amount, etl_time FROM ods_trade_order WHERE dt = '2026-10-11';
-- 分区元数据维护与查看
ALTER TABLE dwd_trade_order_detail_di ADD IF NOT EXISTS PARTITION (dt = '2026-10-12');
SHOW PARTITIONS dwd_trade_order_detail_di;确认分区裁剪是否生效
确认分区裁剪是否生效
-- 好:分区字段直接比较,可裁剪,只扫一天数据
SELECT COUNT(1) FROM dwd_trade_order_detail_di WHERE dt = '2026-10-11';
-- 好:范围条件同样可以裁剪
SELECT COUNT(1) FROM dwd_trade_order_detail_di WHERE dt BETWEEN '2026-10-01' AND '2026-10-11';
-- 差:分区字段被函数包装,无法裁剪,退化为全表扫描
SELECT COUNT(1) FROM dwd_trade_order_detail_di WHERE SUBSTR(dt, 1, 7) = '2026-10';设计选择对照
| 选择 | 好处 | 代价 |
|---|---|---|
| 一级 dt 分区 | 结构简单、写入与清理方便 | 数据量大时单分区依旧很大 |
| 二级分区 | 按地域或小时裁剪更细 | 分区总数成倍增加,元数据与小文件压力上升 |
| 按高基数列分桶 | 连接与采样效率高 | 写入需桶对齐,改桶数要重建表 |
| 粒度过细的分区 | 裁剪面小 | 小文件多,读取时打开文件的开销反超收益 |
分区字段建议用字符串存日期:字符比较可读、便于人工排查,写入时用格式化字符串,避免时区与时间戳转换带来的偏差。
分区数失控(按小时再按渠道再按省份)会让元数据膨胀、小文件遍地,查询规划时间显著变长;分区的第一目标是让常用过滤条件能裁剪,不是切得越细越好。