如何在 Spark SQL 中进行表的分区和分桶?两者的区别是什么?
Spark SQL 表分区与分桶详解
一、表分区(Partitioning)
定义:
通过指定业务相关字段(如日期、地域)将数据物理划分为独立目录存储,实现垂直切分。
核心特性:
- 目录结构映射:
/table/path/partition_column=value/
- 分区裁剪:自动跳过无关分区,减少I/O
- 适用场景:有明显时间范围查询(如
WHERE dt='2023-01-01'
)
创建语法:
-- 静态分区表 CREATE TABLE logs ( user_id STRING, event STRING ) PARTITIONED BY (dt STRING, country STRING) STORED AS PARQUET; -- 动态分区插入 SET spark.sql.sources.partitionOverwriteMode=dynamic; INSERT OVERWRITE TABLE logs PARTITION (dt, country) SELECT user_id, event, dt, country FROM source_table;
二、表分桶(Bucketing)
定义:
通过哈希算法将数据均匀分布到固定数量的文件中,实现水平切分。
核心特性:
- Join加速:相同Bucket Key的数据局部性增强
- 高效聚合:相同Key数据已预聚合
- 适用场景:高频JOIN字段(如
user_id
)、中等基数维度
创建语法:
CREATE TABLE user_orders ( user_id INT, order_id STRING, amount DOUBLE ) CLUSTERED BY (user_id) INTO 32 BUCKETS STORED AS PARQUET; -- 写入时需启用分桶 SET spark.sql.sources.bucketing.enabled=true; INSERT INTO user_orders SELECT * FROM source_table;
三、分区 vs 分桶对比
存储方式 | 按列值划分目录(多级嵌套) | 哈希散列到固定数量文件 |
优化目标 | 快速过滤(分区裁剪) | 提升JOIN/聚合效率 |
适用列特征 | 低基数(如国家、日期) | 高基数且均匀分布(如用户ID) |
文件数量 | 随分区数线性增长(易产生小文件) | 固定数量(可控文件大小) |
查询场景 |
|
/
|
四、联合使用策略
-- 分区+分桶组合优化 CREATE TABLE user_behavior ( user_id INT, event_time TIMESTAMP, action STRING ) PARTITIONED BY (dt STRING) CLUSTERED BY (user_id) INTO 64 BUCKETS STORED AS ORC; -- 查询时双重优化 SELECT * FROM user_behavior WHERE dt='2023-10-01' -- 触发分区裁剪 AND user_id=1001; -- 命中分桶文件
五、注意事项
- 分区陷阱避免超过1000个分区(引发元数据压力)动态分区写入时设置spark.sql.files.maxRecordsPerFile控制文件大小
- 分桶限制要求输出格式支持(Parquet/ORC)写入时需排序保证分桶有效性:
- Spark 3.0+优化启用自适应执行提升分桶效果:
典型应用场景:
电商订单表采用(dt, region)
二级分区 + order_id
分桶,可同时优化时间范围查询和订单详情的JOIN效率。