存储过程
这个IceBerg中非常强大的特性,使用语法为
CALL catalog.system.produce_name( arg_name_2 => arg_2 , arg_name_3 => arg_3)
这是通过名称进行传递参数(推荐),所有的过程都在系统的命名空间中存储
这里我们主要介绍高频使用的存储过程
清理未被元数据引用的孤立文件(remove_orphan_files)
在版本更新的时候,经常会有更新后就不被元数据使用到的文件,这些我们就叫作孤立文件,如果没有被及时清理,这些文件无疑会占用资源,因此该存储过程的适用场景为
- 定期清理写入失败存储的文件
- 解决版本更新未被元数据引用的问题
- 存储优化
- 解决Spark作业崩溃导致的中间文件残留
先是他的参数说明
CALL catalog.system.remove_orphan_files(
table => yours_table -- 访问的表(必选)
,orphan => timestamp -- 时间戳设定(可选),只清除早于该时间戳的孤立文件,要求毫秒级Unix
,location => custom_path -- 限定查找路径(可选),默认全搜索
,dry_run => true/false -- 是否模拟查询结果(可选),true的话返回删除的孤立文件但不实际执行
)
举例使用
-- 安全模式:删除七天前的孤立文件
CALL hive_prod.system.remove_orphan_files(
table => sales_table
,orphan => (current_timestamp.cast('long')*1000 - interval 7 days) * 1000
,dry_run => true
)
-- 实际使用:
CALL hive_prod.system.remove_orphan_files(
table => sales_table
,orphan => (current_timestamp - interval 7 days) * 1000
)
使用建议:
- 窗口时间设置为最近有效的快照时间,避免误删新文件
- 第一次开启安全模式验证结果
- 大表的话,可以通过location来限定路径,进行拆分
合并小文件/优化文件分布!!(rewrite_data_files)
这个存储过程主要用来合并小文件,来提升查询效率,因此在存储过程中非常重要
那我们先来看看他的参数
| 参数分类 | 参数名 | 默认值/规则 | 作用说明 |
|---|---|---|---|
| 策略控制 | strategy | binpack(默认)或 sort | - binpack:仅合并文件,不排序。 - sort:合并并按指定列排序数据。 |
| 排序规则 | sort_order | 默认继承表定义 | - Z-Order:zorder(c1,c2) 优化多维查询。 - 普通排序:c1 ASC NULLS FIRST。 |
| 文件筛选 | where | 无 | 筛选需合并的数据(如 dt='2023-01-01')。 |
| 此处下方皆为OPTION选项内填写 | |||
| 目标文件大小 | target-file-size-bytes | 512 MB | 合并后的目标文件大小。 |
| 文件合并阈值 | min-file-size-bytes | 384 MB(512MB * 75%) | 小于此值的文件强制合并。 |
| 文件拆分阈值 | max-file-size-bytes | 921 MB(512MB * 180%) | 大于此值的文件强制拆分。 |
| 文件组数量阈值 | min-input-files | 5 | 文件组中文件数超过此值时触发合并。 |
| 并发控制 | max-concurrent-file-group-rewrites | 5 | 并行处理的最大文件组数。 |
高级参数调优
| 参数名 | 作用说明 |
|---|---|
partial-progress.enabled | 允许分阶段提交合并结果(避免任务失败全量重试)。 |
rewrite-job-order | 控制合并任务执行顺序(按文件大小、数量升序/降序)。 |
max-file-group-size-bytes | 单文件组最大处理数据量(默认 100GB),避免大分区资源不足。 |
remove-dangling-deletes | 清理无效的 Delete 文件(需额外提交)。 |
delete-ratio-threshold | 仅合并删除比例超过 30% 的文件(优化 Merge-on-Read 性能)。 |
Sort策略特有参数
| 参数 | 高频使用场景 | 默认值适用性 |
|---|---|---|
compression-factor | 高压缩率数据写入 | 中(需校准) |
shuffle-partitions-per-file | 大规模数据排序且内存不足时 | 低 (保持默认) |
- 若发现 rewrite_data_files 生成的文件大小与预期不符(如压缩后数据膨胀),优先调整 compression-factor。
- 若使用 Z-Order 且排序键包含变长列,根据字段实际长度调整 var-length-contribution。
首先是排序规则,涉及到了一个排序策略:Z-order策略
这个主要是将多维的数据拆分为一维数据来映射,在保留原始数据的基础上,能够比传统线性排序更好的优化多维查询
例如:x=3(11), y=5(101) → Z-Address=110111
列选择:优先选择高基数、高频查询的维度(如用户 ID、事件时间)。
数据治理:定期合并小文件(rewrite_data_files)并清理孤立文件,维持存储效率。
混合策略:结合时间分区(如 dt)与 Z-Order,平衡写入性能与查询效率。
适用场景:
- 适合2~4列高频过滤列的复合查询场景
- 适合在OLAP场景下对多维度等值查询的优化
- 当数据均匀的时候,Z-order排序的效率显著优于简单排序
要注意Z-Order重写需要额外的资源,因此最好是低频更新的表
使用例子:
-- 基础配置
CALL catalog.system.rewrite_data_files(
table => 'db.orders',
options => map(
'target-file-size-bytes' , '1073741824' -- 合并为1GB的文件
,'min-file-size-bytes','268435456' --256MB以下的文件强制合并
)
)
-- 排序合并(优化性能)
CALL catalog.system.rewrite_data_files(
table => 'db.logs',
stragery => 'sort',
sort_order => 'zorder(user_id,event_time)', --以z-order的排序来提高性能
options => map(
'target-file-size-bytes','2147483648' -- 合并成2GB的文件
,'max-concurrent-file-group-rewrites',
'10' --提高并行度
)
)
-- 局部合并(分区优化)
CALL catalog.system.rewrite_data_files(
table => 'db.sales',
where => 'dt >= "2023-01-01" AND dt <= "2023-01-07"', -- 合并指定分区
options => map('rewrite-all', 'true') -- 忽略阈值强制合并
);
- sort策略需要消耗额外资源,因此最好在低负载的时候去使用
- 如果大分区,就需要调整max-file-group-size-bytes,避免OOM
在合并之后,旧的文件就成为了孤立文件,咱们就可以用刚才讲的remove_orphan_files去进行清楚操作
清楚不需要的过期快照以及文件(expire_snapshots)
IceBerg每次在进行插入/更新/删除/修改的操作,都会产生新的快照,同时保留旧数据以供时间旅行的实现
expire_snapshots就是用来清理这些旧快照以及被这些旧快照单独引用的数据文件,但是仅删除未被其他快照/标签引用的
介绍一下参数
| 参数名 | 必填 | 类型 | 默认值/行为 |
|---|---|---|---|
table | ✔️ | string | 目标表名(格式:catalog.db.table)。 |
older_than | ❌ | timestamp | 删除早于此时间戳的快照(默认:5天前)。 |
retain_last | ❌ | int | 保留最近的 N个快照(即使早于 older_than,默认 1)。 |
max_concurrent_deletes | ❌ | int | 删除文件的并发线程数(默认无并发,单线程执行)。 |
stream_results | ❌ | boolean | 是否分批次流式传输删除文件到 Spark Driver(默认 false,建议大数据量设为 true 避免 OOM)。 |
snapshot_ids | ❌ | array<long> | 直接指定要删除的快照 ID 列表(需确保非当前快照且未被引用)。 |
delete_orphan_files | ❌ | bollean | 是否同时清理未被任何快照引用的孤立文件,默认为false |
file_scan_task_manifests | ❌ | boolean | 是否扫描清单文件以验证数据是否被引用,默认为true |
光看不行,还得有点操作步骤
-- 删除7天前的快照但是保留十个快照
CALL catalog.system.expire_snapshots(
table => 'db.sample',
older_than => current_timestamp() - INTERVAL '7' DAY,
retain_last => 10
);
-- 安全清理示例(含孤立文件清理)
CALL catalog.system.expire_snapshots(
table => 'db.audit_log',
older_than => TIMESTAMP '2025-05-09 00:00:00',
retain_last => 5,
max_concurrent_deletes => 4,
stream_results => true,
delete_orphan_files => true
);
-- 清理旧元数据文件(需单独执行)
CALL catalog.system.remove_old_metadata(
table => 'db.audit_log',
older_than => TIMESTAMP '2025-01-01'
);
执行顺序:最好是在rewrite_data_files合并小文件后再执行,清理旧快照
- 并发删除数 (max_concurrent_deletes) 建议设为集群可用核数的 1/4
合并清单文件以提高元数据查询效率(merge_manifests)
这个主要是用来合并清单文件,使用的程度并不会像合并数据文件一样那么高
可选的参数有
| 参数名 | 类型 | 作用 |
|---|---|---|
rewrite_all | boolean | 控制是否重写所有清单文件而不仅仅是小的清单文件,但是开启了代表消耗更多的资源(默认false) |
use_caching | boolean | 是否使用缓存来加速合并过程,推荐资源充足的时候开启(默认为true) |
max_manifests_size_bytes | int | 指定合并后的清单文件大小(默认大小为8MB,大集群建议为32MB) |
min_manifests_count | int | 触发合并的最小文件数,建议为5~10避免高频合并 |
适用场景:
- 表经过大量的小文件写入操作后,可以合并一下清单文件提高元数据查询效率
- 读取元数据成为性能瓶颈的时候,可以合并一下
- 每日ETL后,可以作为维护表的一部分执行
-- 合并特定表的清单文件
CALL system.merge_manifests(
table => 'hive_prod.analytics.events'
);
-- 强制重写所有清单文件
CALL system.merge_manifests(
table => 'hive_prod.analytics.events',
rewrite_all => true
);
-- 带完整参数的合并示例
CALL system.merge_manifests(
table => 'hive_prod.analytics.events',
rewrite_all => false,
max_manifest_size_bytes => 16777216, -- 16MB
min_manifest_count => 5
);
但是要注意,合并会导致新的快照出现,历史快照并不会删除,如果要删除还需要配合expire_snapshots
优化合并删除文件(rewrite_position_delete_files)
针对删除文件,可以使用这个存储过程,去合并小位置删除文件,同时移除指向已失效数据文件的删除文件
核心参数有:
| 参数分类 | 参数名 | 默认值 | 核心作用 |
|---|---|---|---|
| 并发控制 | max-concurrent-file-group-rewrites | 5 | 控制同时重写的文件组数量,优化资源利用率(如内存、CPU)。 |
| 文件组拆分 | max-file-group-size-bytes | 100GB | 限制单个文件组处理的数据量,避免大分区导致资源耗尽。 |
| 进度管理 | partial-progress.enabled | false | 允许分批提交结果,提升大规模数据重写的容错性。 |
| 文件大小策略 | target-file-size-bytes | 64MB | 设定输出文件的理想大小,平衡存储效率与查询性能。 |
min-file-size-bytes | 48MB (75%目标值) | 低于此值的文件强制合并,减少碎片。 | |
max-file-size-bytes | 115MB (180%目标值) | 高于此值的文件强制拆分,避免超大文件。 | |
| 重写优先级 | rewrite-job-order | none | 控制文件组处理顺序: • bytes-asc/desc:按大小排序 • files-asc/desc:按文件数排序 • rewrite-ts-asc/desc : 按时间排序 |
| 强制重写 | rewrite-all | false | 忽略其他条件,强制重写所有文件(慎用)。 |
这是执行的流程
1.根据表元数据的内容定位到所有位置删除文件(以.delete结尾的文件)
2.根据文件大小策略去进行拆分或合并,会跳过指向已失效数据文件的删除文件
3.并行处理,根据并发控制去生成合并文件
4。元数据更新,更新Manifestes和快照文件,旧的快照要配合expire_snapshots删除
-- 带合并示例
CALL system.rewrite_position_delete_files(
table => 'hive_prod.analytics.events',
options => map(
'max-concurrent-file-group-rewrites', '10',
'target-file-size-bytes', '67108864', -- 64MB
'partial-progress.enabled', 'true',
'rewrite-job-order', 'bytes-desc'
)
);
迁移数据格式(migrate_table)
将Hive数据格式迁移为IceBerg的表格式,适合在企业技术架构转型的时候去使用
在这个之上,还有一个迁移方式,是migrate,二者的区别是,migrate适合大规模表格式的迁移,migrate_table则是专注于一个表
适合先用migrate进行大规模迁移,再用migrate_table单独优化个别表
捕获数据更新,IceBerg的CDC功能(craete_changelog_view)
这个是IceBerg的CDC功能,也就是用于实时捕获数据更新,通过创建一个视图view来跟踪表的数据变更情况
| 参数名 | 必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
table | ✔️ | string | - | 源表名(需为 Iceberg 表)。 |
changelog_view | string | - | 生成的视图名称,若未指定则返回临时视图。 | |
options | map | - | 指定快照范围(如 start-snapshot-id、end-timestamp)。 | |
net_changes | boolean | false | 是否输出净变更(合并多次更新为最终状态)。 | |
compute_updates | boolean | 自动判断 | 是否计算更新前后的完整行数据(需主键或 identifier_columns)。 | |
identifier_columns | array | 表的主键字段 | 指定用于识别行的唯一字段(若无主键需显式设置) |
start-snapshot-id / end-snapshot-id:按快照 ID 范围过滤变更。
start-timestamp / end-timestamp:按时间戳范围过滤变更(如 ‘2024-01-01 00:00:00’)。
排除故障时,可以指定特定快照IDend-snapshot-id:包含结束快照 ID,默认为 table 的当前快照。start-snapshot-id:独占的启动快照 ID。如果未提供,它将从表的第一个快照中读取。
例子:
--追踪数据变更情况
CALL create_changelog_view(
table => 'db.users',
changelog_view => 'user_changes',
options => map('start-timestamp', '2024-03-01', 'end-timestamp', '2024-03-31')
);
--增量数据同步
-- 获取净变更(仅最终状态)
CALL create_changelog_view(
table => 'db.orders',
net_changes => true,
identifier_columns => array('order_id')
);
--故障恢复和回溯
-- 分析订单表在快照 12345 到 67890 之间的所有更新
CALL create_changelog_view(
table => 'db.orders',
options => map('start-snapshot-id', '12345', 'end-snapshot-id', '67890'),
compute_updates => true
);
具体实例场景
-- 假设有一个 Iceberg 表 iceberg_db.orders,记录订单数据(含字段 order_id、amount、status),现需捕获 2024-03-01 至 2024-03-31 期间的所有变更(插入、更新、删除)
-- 创建变更日志视图,包含更新前后的完整行数据
CALL catalog.system.create_changelog_view(
table => 'iceberg_db.orders',
changelog_view => 'orders_changelog',
options => map(
'start-timestamp', '2024-03-01 00:00:00',
'end-timestamp', '2024-03-31 23:59:59'
),
compute_updates => true,
identifier_columns => array('order_id')
);
执行SELECT * FROM orders_changelog LIMIT 3
_change_type | _commit_snapshot | order_id | amount | status |
|---|---|---|---|---|
INSERT | 123456 | 1001 | 99.99 | PAID |
UPDATE_BEFORE | 123457 | 1002 | 50.00 | PENDING |
UPDATE_AFTER | 123457 | 1002 | 50.00 | CANCELLED |
统计表中非重复值的统计数据(compute_table_stats)
| Argument Name | Required | Type | Description |
|---|---|---|---|
table | ✔️ | string | 表的名称 |
snapshot_id | string | 用于收集统计信息的快照的 ID | |
columns | array | 用于收集统计信息的列 |
例子:
CALL catalog_name.system.compute_table_stats('my_table');
CALL catalog_name.system.compute_table_stats(table => 'my_table', snapshot_id => 'snap1' );
CALL catalog_name.system.compute_table_stats(table => 'my_table', snapshot_id => 'snap1', columns => array('col1', 'col2'));
&spm=1001.2101.3001.5002&articleId=147980187&d=1&t=3&u=ff21042d77de4364b003611b22b7281b)
552

被折叠的 条评论
为什么被折叠?



