使用引擎进行表维护
建议一:定期执行快照过期清理
原因:每次写/更新/删除/Upsert/压缩都会产生新快照,不清理会导致存储持续增长。
实现方式:
-- 清理超过7天的快照,保留最近100个 CALL spark_catalog.system.expire_snapshots( table => 'db.table', older_than => CURRENT_TIMESTAMP - INTERVAL '7' DAYS, retain_last => 100, stream_results => true -- 防止大数据量导致Driver OOM ); -- 清理特定快照 CALL spark_catalog.system.expire_snapshots( table => 'db.table', snapshot_ids => ARRAY(123) ); -- 清理时同时清理未使用的元数据 CALL spark_catalog.system.expire_snapshots( table => 'db.table', older_than => TIMESTAMP '2024-01-01 00:00:00', clean_expired_metadata => true );
注意:
- 分支和标签默认永不过期,需通过表属性history.expire.max-ref-age-ms配置。
- 建议设置stream_results=>true,避免大数据量时Driver OOM。
Aura实现方式:参考iceberg_expire_snapshots表服务。具体语法请参考:Iceberg表服务函数。
建议二:定期清理孤立文件
原因:清理不再被任何元数据文件引用的"孤儿"文件,释放存储空间。
实现方式:
-- 先干跑查看待清理文件(推荐生产环境先执行) CALL spark_catalog.system.remove_orphan_files( table => 'db.table', dry_run => true ); -- 实际清理(清理超过7天的孤立文件) CALL spark_catalog.system.remove_orphan_files( table => 'db.table', older_than => CURRENT_TIMESTAMP - INTERVAL '7' DAYS ); -- 清理特定目录下的孤立文件 CALL spark_catalog.system.remove_orphan_files( table => 'db.table', location => 'table_location/data' );
Aura实现方式:参考iceberg_remove_orphanfiles表服务。具体语法请参考:Iceberg表服务函数。
建议三:定期执行数据文件压缩
原因:小文件过多会导致大量元数据开销和文件打开成本,影响查询性能。
实现方式:
-- 默认binpack策略(合并小文件)
CALL spark_catalog.system.rewrite_data_files('db.table');
-- 排序策略(按指定列排序)
CALL spark_catalog.system.rewrite_data_files(
table => 'db.table',
strategy => 'sort',
sort_order => 'id DESC NULLS LAST, name ASC NULLS FIRST'
);
-- Z-Order优化(多列交织排序,提升多列查询性能)
CALL spark_catalog.system.rewrite_data_files(
table => 'db.table',
strategy => 'sort',
sort_order => 'zorder(c1,c2,c3)'
);
-- 启用部分提交和清理dangling deletes
CALL spark_catalog.system.rewrite_data_files(
table => 'db.table',
options => map(
'min-input-files', '2',
'remove-dangling-deletes', 'true',
'partial-progress.enabled', 'true'
)
); 关键参数:
- target-file-size-bytes: 目标文件大小(默认512MB)
- min-input-files:触发重写的最小文件数(默认5)
- rewrite-job-order:排序策略(bytes-asc/desc,files-asc/desc)
Aura实现方式:
Aura中通过OPTIMIZE语法对目标表的指定数据进行重写。
OPTIMIZE table_name REWRITE DATA
[ WITH OPTIONS (option_key = option_value [, ...]) ]
[ WHERE condition ]
[ ORDER BY target_list [ ASC | DESC ] ] 参数说明:
- table_name:目标表的名字。取值范围:已存在的表名。
- condition:一个返回boolean值的表达式,用于判断哪些文件需要被重写。
- target_list:数据重写的排序键。
- option_key、option_value:数据重写的配置选项。
建议四:定期重写Manifest文件
原因:优化查询规划性能,manifest中的数据文件按分区规范字段排序。
实现方式:
-- 重写manifest
CALL spark_catalog.system.rewrite_manifests('db.table');
-- 指定分区规范
CALL spark_catalog.system.rewrite_manifests(
table => 'db.table',
spec_id => 1
); Aura实现方式:参考iceberg_rewrite_manifests表服务。具体语法请参考:Iceberg表服务函数。
建议五:定期重写Position Delete文件
原因:压缩小position delete文件,清理dangling deletes(指向已不存在数据文件的删除记录)。
实现方式:
-- 压缩并清理dangling deletes
CALL spark_catalog.system.rewrite_position_delete_files('db.table');
-- 强制重写所有文件
CALL spark_catalog.system.rewrite_position_delete_files(
table => 'db.table',
options => map('rewrite-all', 'true')
); 建议六:为重要版本创建标签
原因:便于快速回滚到特定版本,避免误操作后无法恢复。
实现方式:
-- 切换到指定快照
CALL spark_catalog.system.set_current_snapshot(
table => 'db.table',
snapshot_id => 123
);
-- 切换到标签
CALL spark_catalog.system.set_current_snapshot(
table => 'db.table',
ref => 'my_tag'
);
-- 回滚到指定快照
CALL spark_catalog.system.rollback_to_snapshot('db.table', 1);
-- 按时间回滚
CALL spark_catalog.system.rollback_to_timestamp(
'db.table',
TIMESTAMP '2024-06-30 00:00:00.000'
); Aura实现方式:参考iceberg_set_current_snapshot、iceberg_rollback_to_snapshot、iceberg_rollback_to_timestamp表服务。具体语法请参考:Iceberg表服务函数。
建议七:迁移前使用快照表测试
原因:创建轻量级临时副本用于测试,不影响源表,避免迁移风险。
实现方式:
-- 创建快照表
CALL spark_catalog.system.snapshot('db.source_table', 'db.snapshot_table'); 注意:快照表不是数据文件的唯一所有者,无法执行expire_snapshots物理删除文件。
建议八:正式迁移使用migrate
原因:将现有Hive/Spark表替换为Iceberg表,保留原表作为备份。
实现方式:
-- 迁移并添加属性
CALL spark_catalog.system.migrate(
'db.old_table',
map('foo', 'bar')
);
-- 不保留备份
CALL spark_catalog.system.migrate(
table => 'db.old_table',
drop_backup => true
); 建议九:计算表统计信息
原因:收集列的NDV(不同值数量)统计信息,优化查询计划。
实现方式:
-- 计算全表统计
CALL spark_catalog.system.compute_table_stats('db.table');
-- 指定快照和列
CALL spark_catalog.system.compute_table_stats(
table => 'db.table',
snapshot_id => 'snap1',
columns => array('col1', 'col2')
); 建议十:计算分区统计信息
原因:增量收集分区统计信息,提升分区裁剪效率。
实现方式:
-- 计算分区统计
CALL spark_catalog.system.compute_partition_stats('db.table');
-- 指定快照
CALL spark_catalog.system.compute_partition_stats(
table => 'db.table',
snapshot_id => 'snap1'
);