
# 使用引擎进行表维护
#### 建议一：定期执行快照过期清理
**原因**：每次写/更新/删除/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表服务函数](https://support.huaweicloud.com/sqlref-aura-aidatalake/aidatalake_061_0198.html)。
#### 建议二：定期清理孤立文件
**原因**：清理不再被任何元数据文件引用的"孤儿"文件，释放存储空间。
**实现方式**：
```
-- 先干跑查看待清理文件（推荐生产环境先执行）
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表服务函数](https://support.huaweicloud.com/sqlref-aura-aidatalake/aidatalake_061_0198.html)。
#### 建议三：定期执行数据文件压缩
**原因**：小文件过多会导致大量元数据开销和文件打开成本，影响查询性能。
**实现方式**：
```
-- 默认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表服务函数](https://support.huaweicloud.com/sqlref-aura-aidatalake/aidatalake_061_0198.html)。
#### 建议五：定期重写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表服务函数](https://support.huaweicloud.com/sqlref-aura-aidatalake/aidatalake_061_0198.html)。
#### 建议七：迁移前使用快照表测试
**原因**：创建轻量级临时副本用于测试，不影响源表，避免迁移风险。
**实现方式**：
```
-- 创建快照表 
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' 
);
```
