1. 行级更新时,Merge into减少 I/O
基本区别
INSERT OVERWRITE
- 功能:将整个表或分区内的数据替换为新的数据集。
- 操作方式:重写目标分区内的所有文件,即使只对部分数据更新,需要重写所有文件。
- 开销:重写大量数据文件会导致高 I/O 开销和时间消耗,对大规模数据集不友好。
MERGE INTO
- 功能:根据条件从源数据集更新、插入或删除目标表中的数据。
- 操作方式:仅对满足条件的数据行进行更新或插入,其他数据不受影响。
- 开销:只对部分数据行操作,降低 I/O 和计算开销,更加高效。
示例对比
INSERT OVERWRITE
示例
INSERT OVERWRITE TABLE target_table
SELECT * FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY key_column ORDER BY update_time_column DESC) AS row_num
FROM source_table
) tmp
WHERE row_num = 1
UNION ALL
SELECT * FROM target_table t
WHERE NOT EXISTS (
SELECT 1 FROM source_table s WHERE t.key_column = s.key_column
);
该示例会重写整个 target_table
。
MERGE INTO
示例
MERGE INTO target_table AS t
USING (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY key_column ORDER BY update_time_column DESC) AS row_num
FROM source_table
) AS s
ON t.key_column = s.key_column
WHEN MATCHED AND s.row_num = 1 THEN
UPDATE SET t.column1 = s.column1,
t.column2 = s.column2,
t.update_time_column = s.update_time_column
WHEN NOT MATCHED THEN
INSERT (key_column, column1, column2, update_time_column)
VALUES (s.key_column, s.column1, s.column2, s.update_time_column);
MERGE INTO
提供增量更新,适用于流批一体场景,减少变更数据量,避免积压。
2. Distribute
1. 减少小文件
- 适用于 Iceberg 扩展语法,按分区减少小文件写入。
ALTER TABLE prod.db.sample WRITE DISTRIBUTED BY PARTITION;
与手动修改 write.distribution-mode=hash
的效果相同。
ALTER TABLE prod.db.sample SET TBLPROPERTIES (
'write.distribution-mode'='hash'
);
2. Spark Append、Overwrite
- Spark 的
insert into
或insert overwrite
可以手动进行分布。
INSERT OVERWRITE TABLE target_table
SELECT * FROM source_table
DISTRIBUTE BY date;
解决数据倾斜:
INSERT OVERWRITE TABLE target_table
SELECT * FROM source_table
DISTRIBUTE BY date, CAST(RAND()*N AS INT);
分区为多级
- 如果分区为多级(如
PARTITIONED BY date, type
),直接选择分区:date, type
。
分区为一级
- 针对一级分区(如只有时间分区
date
),添加随机值:
DISTRIBUTE BY {表分区列}, CAST(RAND()*N AS INT);
建议 N = 数据量 / 256MB,也就是一个文件256M左右。
3. 排序写入(Order By)
全局排序
- 使用 DDL 设置表的 ordered,配置后写入时会全局排序。
ALTER TABLE prod.db.sample WRITE ORDERED BY category, id;
其他排序选项
- 可以指定排序方向和 NULL 排序:
ALTER TABLE prod.db.sample WRITE ORDERED BY category ASC, id DESC;
ALTER TABLE prod.db.sample WRITE UNORDERED;
数据影响
- 设置
WRITE ORDERED BY
仅影响新写入数据的布局,不会对现有数据进行自动排序,直到显式使用OPTIMIZE
。
OPTIMIZE table_name [WHERE predicate] [ORDER BY columns] [ZORDER BY columns];
参数说明
- table_name:要优化的表名。
- WHERE predicate:可选,限制要优化的分区或数据行。
- ORDER BY columns:可选,指定结果文件的排序方式。
- ZORDER BY columns:可选,设置 Z-Ordering,以优化特定列的查询性能。
注意事项
- 尽管
WRITE ORDERED BY
能提高后续查询性能,但可能增加写入延迟。合理选择排序列对性能有重要影响。
分区与排序结合
- 可以将
WRITE ORDERED BY
与分区相结合进一步提高性能,确保分区内部有序写入。
任务内排序
- 类似于 Spark 的
sort by
,仅适用于MERGE INTO
、UPDATE
、DELETE
。
ALTER TABLE prod.db.sample WRITE LOCALLY ORDERED BY category, id;
插入和覆盖
- 使用手动排序:
INSERT OVERWRITE TABLE target_table SELECT * FROM source_table SORT BY date;
建立集群优先选择
- 推荐使用
CLUSTER BY
(cluster by = distribute by + sort by)。解决数据倾斜:
INSERT OVERWRITE TABLE target_table SELECT * FROM source_table CLUSTER BY date;
以上是关于 Apache Iceberg 数据操作的优化指南,包括行级更新、数据分布和排序写入策略。通过这些策略,可以显著提升数据处理性能和存储效率。