亚马逊AWS官方博客

新功能:借助 sort 和 z-order 压缩提升 Amazon S3 中 Apache Iceberg 的查询性能

现在,您可以使用 sortz-order 压缩来提升 Amazon S3 表类数据存储服务通用 S3 存储桶Apache Iceberg 的查询性能。

通常,您会使用 Iceberg 在 Amazon Simple Storage Service(Amazon S3)中通过 AWS Glue Data Catalog或 S3 表类数据存储服务来管理大规模分析数据集。Iceberg 表支持并发流式传输和批处理摄取、架构演进和时间旅行等使用案例。在处理高摄取量或频繁更新的数据集时,数据湖可能会累积许多小文件,这会影响查询的成本和性能。您分享过,优化 Iceberg 数据布局在操作上较为复杂,通常需要开发和维护自定义管道。尽管默认的 binpack 策略与托管压缩提供了显著的性能提升,但为 S3 和 S3 表类数据存储服务引入 sortz-order 压缩选项,能为跨一个或多个维度筛选的查询带来更大的收益。

两种新的压缩策略:Sortz-order

为帮助您更高效地组织数据,现在,除了默认的 binpack 压缩外,Amazon S3 还支持两种新的压缩策略:sortz-order 压缩。通过 AWS Glue Data Catalog 优化功能,这些高级策略可同时适用于完全托管的 S3 表类数据存储服务和通用 S3 存储桶中的 Iceberg 表。

Sort 压缩根据用户定义的列顺序组织文件。当表定义了排序顺序时,S3 表类数据存储服务压缩会在压缩过程中使用该顺序将相似值聚集在一起。这样可以减少扫描的文件数量,从而提高查询执行效率。例如,如果表按 statezip_code 列进行 sort 压缩,那么筛选这些列的查询扫描的文件会更少,从而缩短延迟并降低查询引擎成本。

Z-order 压缩进一步支持跨多个维度的高效文件剪枝。它将多列值的二进制表示交织成一个可排序的标量,这使得该策略特别适用于空间或多维查询。例如,如果工作负载包含同时按 pickup_locationdropoff_locationfare_amount 筛选的查询,那么与传统基于排序的布局相比,z-order 压缩可减少扫描的文件总数。

S3 表类数据存储服务使用 Iceberg 表元数据来确定当前排序顺序。如果表已定义排序顺序,则无需额外配置即可激活 sort 压缩 — 它会在持续维护期间自动应用。要使用 z-order,您需要通过 S3 表类数据存储服务 API 更新表维护配置,并将策略设置为 z-order。对于通用 S3 存储桶中的 Iceberg 表,您可以通过更新压缩设置,配置 AWS Glue Data Catalog 在优化期间使用 sortz-order 压缩。

只有启用 sortz-order 后写入的新数据会受影响。现有压缩文件将保持不变,除非您通过在表维护设置中增加目标文件大小或使用标准 Iceberg 工具重写数据来显式重写它们。此行为旨在让您控制数据重组的时间和规模,从而平衡成本与性能。

实际操作

我将通过 Apache Spark 和 AWS 命令行界面(AWS CLI)向您演示一个简化示例。我有一个已安装的 Spark 集群和一个 S3 表存储桶。我在 testnamespace 中有一个名为 testtable 的表。我暂时禁用了压缩,以便向表中添加数据。

添加数据后,我检查了表的文件结构。

spark.sql("""
  SELECT 
    substring_index(file_path, '/', -1) as file_name,
    record_count,
    file_size_in_bytes,
    CAST(UNHEX(hex(lower_bounds[2])) AS STRING) as lower_bound_name,
    CAST(UNHEX(hex(upper_bounds[2])) AS STRING) as upper_bound_name
  FROM ice_catalog.testnamespace.testtable.files
  ORDER BY file_name
""").show(20, false)
+--------------------------------------------------------------+------------+------------------+----------------+----------------+
|file_name                                                     |record_count|file_size_in_bytes|lower_bound_name|upper_bound_name|
+--------------------------------------------------------------+------------+------------------+----------------+----------------+
|00000-0-66a9c843-5a5c-407f-8da4-4da91c7f6ae2-0-00001.parquet  |1           |837               |Quinn           |Quinn           |
|00000-1-b7fa2021-7f75-4aaf-9a24-9bdbb5dc08c9-0-00001.parquet  |1           |824               |Tom             |Tom             |
|00000-10-00a96923-a8f4-41ba-a683-576490518561-0-00001.parquet |1           |838               |Ilene           |Ilene           |
|00000-104-2db9509d-245c-44d6-9055-8e97d4e44b01-0-00001.parquet|1000000     |4031668           |Anjali          |Tom             |
|00000-11-27f76097-28b2-42bc-b746-4359df83d8a1-0-00001.parquet |1           |838               |Henry           |Henry           |
|00000-114-6ff661ca-ba93-4238-8eab-7c5259c9ca08-0-00001.parquet|1000000     |4031788           |Anjali          |Tom             |
|00000-12-fd6798c0-9b5b-424f-af70-11775bf2a452-0-00001.parquet |1           |852               |Georgie         |Georgie         |
|00000-124-76090ac6-ae6b-4f4e-9284-b8a09f849360-0-00001.parquet|1000000     |4031740           |Anjali          |Tom             |
|00000-13-cb0dd5d0-4e28-47f5-9cc3-b8d2a71f5292-0-00001.parquet |1           |845               |Olivia          |Olivia          |
|00000-134-bf6ea649-7a0b-4833-8448-60faa5ebfdcd-0-00001.parquet|1000000     |4031718           |Anjali          |Tom             |
|00000-14-c7a02039-fc93-42e3-87b4-2dd5676d5b09-0-00001.parquet |1           |838               |Sarah           |Sarah           |
|00000-144-9b6d00c0-d4cf-4835-8286-ebfe2401e47a-0-00001.parquet|1000000     |4031663           |Anjali          |Tom             |
|00000-15-8138298d-923b-44f7-9bd6-90d9c0e9e4ed-0-00001.parquet |1           |831               |Brad            |Brad            |
|00000-155-9dea2d4f-fc98-418d-a504-6226eb0a5135-0-00001.parquet|1000000     |4031676           |Anjali          |Tom             |
|00000-16-ed37cf2d-4306-4036-98de-727c1fe4e0f9-0-00001.parquet |1           |830               |Brad            |Brad            |
|00000-166-b67929dc-f9c1-4579-b955-0d6ef6c604b2-0-00001.parquet|1000000     |4031729           |Anjali          |Tom             |
|00000-17-1011820e-ee25-4f7a-bd73-2843fb1c3150-0-00001.parquet |1           |830               |Noah            |Noah            |
|00000-177-14a9db71-56bb-4325-93b6-737136f5118d-0-00001.parquet|1000000     |4031778           |Anjali          |Tom             |
|00000-18-89cbb849-876a-441a-9ab0-8535b05cd222-0-00001.parquet |1           |838               |David           |David           |
|00000-188-6dc3dcca-ddc0-405e-aa0f-7de8637f993b-0-00001.parquet|1000000     |4031727           |Anjali          |Tom             |
+--------------------------------------------------------------+------------+------------------+----------------+----------------+
only showing top 20 rows

我观察到该表是由多个小文件组成的,而且新文件的上下界存在重叠 — 数据显然未排序。

我设置了表的排序顺序。

spark.sql("ALTER TABLE ice_catalog.testnamespace.testtable WRITE ORDERED BY name ASC")

我启用了表压缩(默认情况下处于启用状态;我在演示开始时将其禁用了)

aws s3tables put-table-maintenance-configuration --table-bucket-arn ${S3TABLE_BUCKET_ARN} --namespace testnamespace --name testtable --type icebergCompaction --value "status=enabled,settings={icebergCompaction={strategy=sort}}"

然后,等待下一个压缩作业触发。压缩作业会在一天中存在足够多的小文件时运行。可通过以下命令检查压缩状态。

aws s3tables get-table-maintenance-job-status --table-bucket-arn ${S3TABLE_BUCKET_ARN} --namespace testnamespace --name testtable

压缩完成后,再次检查组成表的文件。我看到数据已压缩为两个文件,上下界显示这两个文件中的数据已排序。

spark.sql("""
  SELECT 
    substring_index(file_path, '/', -1) as file_name,
    record_count,
    file_size_in_bytes,
    CAST(UNHEX(hex(lower_bounds[2])) AS STRING) as lower_bound_name,
    CAST(UNHEX(hex(upper_bounds[2])) AS STRING) as upper_bound_name
  FROM ice_catalog.testnamespace.testtable.files
  ORDER BY file_name
""").show(20, false)
+------------------------------------------------------------+------------+------------------+----------------+----------------+
|file_name                                                   |record_count|file_size_in_bytes|lower_bound_name|upper_bound_name|
+------------------------------------------------------------+------------+------------------+----------------+----------------+
|00000-4-51c7a4a8-194b-45c5-a815-a8c0e16e2115-0-00001.parquet|13195713    |50034921          |Anjali          |Kelly           |
|00001-5-51c7a4a8-194b-45c5-a815-a8c0e16e2115-0-00001.parquet|10804307    |40964156          |Liza            |Tom             |
+------------------------------------------------------------+------------+------------------+----------------+----------------+

文件数量减少、大小增大,且指定排序列的数据聚集效果更好。

为使用 z-order,我按照相同的步骤操作,但在维护配置中设置了 strategy=z-order

区域可用性

Sortz-order 压缩现已在所有支持 Amazon S3 表类数据存储服务的 AWS 区域,以及支持通过 AWS Glue Data Catalog 优化的通用 S3 存储桶中可用。除了现有的使用和维护费用外,S3 表类数据存储服务不收取额外费用。对于 Data Catalog 优化,压缩期间会产生计算费用。

通过这些更改,按 sortz-order 列筛选的查询将受益于更快的扫描速度和更低的引擎成本。根据我的经验,从 binpack 切换到 sortz-order 时,查询性能提升可达三倍或更多,具体取决于数据布局和查询模式。欢迎分享您在实际数据中获得的收益。

要了解更多信息,请访问 Amazon S3 表类数据存储服务产品页面或查看 S3 表类数据存储服务维护文档。您也可以立即使用 S3 表类数据存储服务 API 或 AWS Glue 优化功能,在自己的表上测试新策略。

— seb


*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您了解行业前沿技术和发展海外业务选择推介该服务。