适用于 Apache Iceberg 的 BigQuery 表

若要在预览版期间获得支持,请发送电子邮件至 bigquery-tables-for-apache-iceberg-help@google.com

适用于 Apache Iceberg 的 BigQuery 表(以下称为“Iceberg 表”)为在 Google Cloud上构建开放格式湖仓一体提供了基础。Iceberg 表提供与 BigQuery 表相同的全托管式体验,但使用 Parquet 将数据存储在客户拥有的存储桶中,以便与 Iceberg 开放表格式进行互操作。

适用于 Apache Iceberg 的 BigQuery 表与适用于 Apache Iceberg 的 BigLake 外部表不同,因为只有适用于 Apache Iceberg 的 BigQuery 表可以在 BigQuery 中直接修改。适用于 Apache Iceberg 的 BigLake 外部表是通过其他查询引擎(例如 Apache Spark)生成的只读表,并且只能使用 BigQuery 进行查询。

Iceberg 表支持以下功能:

  • 使用 GoogleSQL 数据操纵语言 (DML) 进行表变更。
  • 通过 Spark、Dataflow 和其他引擎等 BigLake 连接器使用 Storage Write API 进行统一批处理和高吞吐量流式处理。
  • 架构演变:您可以添加、删除和重命名列,以满足您的需求。借助此功能,您还可以更改现有列的数据类型列模式。如需了解详情,请参阅类型转换规则
  • 自动存储优化,包括自适应文件大小调整、自动聚簇、垃圾回收和元数据优化。
  • 列级安全性数据遮盖

下面比较了 BigQuery Iceberg 表与 BigQuery 中的其他类似表类型:

标准 BigQuery 表 BigLake 外部表 适用于 Apache Iceberg 的 BigLake 外部表(也称为 BigLake Iceberg 表) BigQuery metastore Iceberg 表预览版 适用于 Apache Iceberg 的 BigQuery 表(也称为 Iceberg 托管式表 / BigQuery Iceberg 表)(预览版
主要特性 全托管式体验 受管控(精细的访问权限控制)且跨开源和 BigQuery 引擎正常运行 BigLake 外部表功能 + 数据一致性、架构更新。无法通过 Spark 或其他开放引擎创建。 BigLake Iceberg 表功能 + 可通过外部引擎更改。无法使用 DDL 或 bq 命令行工具创建。 BigLake Iceberg 表功能 + 开放数据和元数据的管理开销较低
数据存储 BigQuery 代管式存储空间 托管在用户管理的存储桶中的开放格式数据
开放模型 BigQuery Storage Read API(通过连接器) 开放文件格式 (Parquet) 开放库 (Iceberg) 开源兼容(Iceberg metadata 快照)
治理 统一的 BigQuery 治理
写入(DML 和流式处理) 通过 BigQuery 连接器、API、高吞吐量 DML、CDC 仅通过外部引擎写入 通过 BigQuery 连接器、API、高吞吐量 DML、CDC

架构

Iceberg 表可为位于您自己的云存储桶中的表提供 BigQuery 资源管理的便利。Iceberg 表可让您在这些表上使用 BigQuery,而无需将数据从您控制的存储桶中移出。

下图简要展示了托管式表架构: BigQuery for Iceberg 表架构图。

此表管理会对存储桶产生以下影响:

  • BigQuery 会在存储桶中创建新的数据文件,以响应写入请求和后台存储优化(例如 DML 语句和流式处理)。
  • 当您在 BigQuery 中删除托管式表时,BigQuery 不会删除关联的数据文件。您必须通过手动从存储桶中删除文件和所有导出的表元数据来确认删除。
  • Iceberg 表不会产生 BigQuery 存储费用。如需了解详情,请参阅结算

创建 Iceberg 表与创建 BigQuery 表类似。由于 Iceberg 表以开放格式在 Cloud Storage 上存储数据,因此在以下方面提供更多选项:

  • 使用 WITH CONNECTION 指定 Cloud 资源连接,以便为 BigLake 访问 Cloud Storage 配置连接凭据。
  • 使用 file_format 指定数据存储的文件格式。预览版支持 PARQUET
  • 使用 table_format 指定开源元数据表格式。预览版支持 ICEBERG

最佳做法

在 BigQuery 外部直接更改文件或向存储桶添加文件可能会导致数据丢失或不可恢复的错误。下表介绍了可能的场景:

操作 结果 预防措施
向 BigQuery 外部的存储桶添加新文件。 数据丢失:BigQuery 不会跟踪在 BigQuery 外部添加的新文件或对象。未跟踪的文件会由后台垃圾回收进程删除。 仅通过 BigQuery 添加数据。这可让 BigQuery 跟踪这些文件并防止它们被垃圾回收。
为防止意外添加和数据丢失,我们还建议您限制对包含 Iceberg 表的存储桶的外部工具写入权限。
在非空前缀中创建新的 Iceberg 表。 数据丢失:BigQuery 不会跟踪现有数据,因此这些文件会被视为未跟踪,并由后台垃圾回收进程删除。 仅在空前缀中创建新的 Iceberg 表。
修改或替换 Iceberg 表数据文件。 数据丢失:在外部修改或替换时,表会无法通过一致性检查,并且变得不可读。对表进行的查询会失败。
您无法通过自助方式从这个时间点恢复。如需数据恢复方面的帮助,请与支持团队联系。
仅通过 BigQuery 修改数据。这可让 BigQuery 跟踪这些文件并防止它们被垃圾回收。
为防止意外添加和数据丢失,我们还建议您限制对包含 Iceberg 表的存储桶的外部工具写入权限。
在相同或重叠的 URI 上创建两个适用于 Apache Iceberg 的 BigQuery 表。 数据丢失:BigQuery 不会桥接 Iceberg 表的相同 URI 实例。 每个表的后台垃圾回收进程都会将相反表的文件视为未跟踪,并将其删除,从而导致数据丢失。 为每个 Iceberg 表使用唯一的 URI。

位置注意事项

您可以使用 Cloud Storage 单区域双区域存储桶(而不是多区域存储桶)来提高性能。

结算

以下功能使用现有已发布的价格计费:

  • Cloud Storage 价格,适用于存储在 Cloud Storage 存储桶中的所有数据、Cloud Storage 执行的数据处理,以及从存储桶读取的数据量的网络用量。
  • BigQuery 计算价格,适用于查询、DML 和后台存储优化(包括聚簇、合并和垃圾回收)。
    • 预留(槽)的使用费用遵循现有的槽价格。
    • 使用按需库存单位 (SKU) 的费用遵循现有的按需价格。如需了解详情,请参阅 BigLake 费用
  • 批量加载提取计算使用按需 SKU 或预留(槽)计费。
  • Storage Read API 价格,适用于通过 Read API 从 Spark 读取数据。
  • Storage Write API 价格,适用于流式处理。

Iceberg 表工作流

以下部分介绍了如何创建、加载、管理和查询托管式表。

准备工作

在创建和使用 Iceberg 表之前,请确保您已设置与存储桶的 Cloud 资源连接。您的连接需要具有对存储桶的写入权限,如以下所需角色部分中所述。

所需的角色

如需获得让 BigQuery 管理项目中的表所需的权限,请让您的管理员为您授予以下 IAM 角色:

如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

这些预定义角色可提供让 BigQuery 管理项目中的表所需的权限。如需查看所需的确切权限,请展开所需权限部分:

所需权限

让 BigQuery 管理项目中的表需要以下权限:

  • 针对您的项目的 bigquery.connections.delegate 权限
  • 针对您的项目的 bigquery.jobs.create 权限
  • 针对您的项目的 bigquery.readsessions.create 权限
  • 针对您的项目的 bigquery.tables.create 权限
  • 针对您的项目的 bigquery.tables.get 权限
  • 针对您的项目的 bigquery.tables.getData 权限
  • 针对存储桶的 storage.buckets.get 权限
  • 针对存储桶的 storage.objects.create 权限
  • 针对存储桶的 storage.objects.delete 权限
  • 针对存储桶的 storage.objects.get 权限
  • 针对存储桶的 storage.objects.list 权限

您也可以使用自定义角色或其他预定义角色来获取这些权限。

创建 Iceberg 表

如需创建 Iceberg 表,请选择以下方法之一:

SQL

CREATE TABLE [PROJECT_NAME.]DATASET_NAME.TABLE_NAME (
COLUMN DATA_TYPE[, ...]
)
CLUSTER BY CLUSTER_COLUMN_LIST
WITH CONNECTION CONNECTION_NAME
OPTIONS (
file_format = 'PARQUET',
table_format = 'ICEBERG',
storage_uri = 'STORAGE_URI');

替换以下内容:

  • PROJECT_NAME:包含数据集的项目。如果未定义,该命令会假定为默认项目。
  • DATASET_NAME:现有数据集。
  • TABLE_NAME:您要创建的表的名称。
  • DATA_TYPE:列中包含的信息的数据类型。
  • CLUSTER_COLUMN_LIST:以英文逗号分隔的列表,最多包含四个列。它们必须是顶级非重复列。
  • CONNECTION_NAME:连接的名称。 例如 myproject.us.myconnection
  • STORAGE_URI:完全限定的 Cloud Storage URI。例如 gs://mybucket/table

bq

bq --project_id=PROJECT_NAME mk \
    --file_format=PARQUET \
    --table_format=ICEBERG \
    --connection_id=CONNECTION_NAME \
    --storage_uri=STORAGE_URI \
    --schema=COLUMN_NAME:DATA_TYPE[, ...] \
    --clustering_fields=CLUSTER_COLUMN_LIST \
    MANAGED_TABLE_NAME

替换以下内容:

  • PROJECT_NAME:包含数据集的项目。如果未定义,该命令会假定为默认项目。
  • CONNECTION_NAME:连接的名称。 例如 myproject.us.myconnection
  • STORAGE_URI:完全限定的 Cloud Storage URI。例如 gs://mybucket/table
  • COLUMN_NAME:列名称。
  • DATA_TYPE:列中包含的信息的数据类型。
  • CLUSTER_COLUMN_LIST:以英文逗号分隔的列表,最多包含四个列。它们必须是顶级非重复列。
  • MANAGED_TABLE_NAME:您要创建的表的名称。

API

使用定义的表资源调用 tables.insert 方法,如下所示:

{
"tableReference": {
  "tableId": "TABLE_NAME"
},
"biglakeConfiguration": {
  "connectionId": "CONNECTION_NAME",
  "fileFormat": "PARQUET",
  "tableFormat": "ICEBERG",
  "storageUri": "STORAGE_URI"
},
"schema": {
  "fields": [
    {
      "name": "COLUMN_NAME",
      "type": "DATA_TYPE"
    }
    [, ...]
  ]
}
}

替换以下内容:

  • TABLE_NAME:您要创建的表的名称。
  • CONNECTION_NAME:连接的名称。 例如 myproject.us.myconnection
  • STORAGE_URI:完全限定的 Cloud Storage URI通配符也受支持。 例如 gs://mybucket/table
  • COLUMN_NAME:列名称。
  • DATA_TYPE:列中包含的信息的数据类型。

将数据导入 Iceberg 表

以下部分介绍了如何将数据从各种表格式导入 Iceberg 表中。

从 Parquet 文件快速加载

借助 copy_files_only 选项,您可以通过复制现有的 Parquet 文件(而不是读取内容并将内容重写为新文件)来更快地加载数据。与常规文件加载相比,快速加载使用更少的计算容量。Parquet 文件必须与 Apache Iceberg 规范兼容,并且包含完整的列统计信息。快速加载不会检测文件中的无效值(例如超出范围的时间戳),因为系统不会读取和重新处理文件。如需详细了解如何加载 Parquet 文件,请参阅将 Parquet 数据加载到新表中

如需将平面 Parquet 文件快速加载到现有 Iceberg 表中,请使用 bq load 命令

bq load \
    --copy_files_only \
    --source_format=PARQUET \
    DATASET_NAME.TABLE_NAME \
    PATH_TO_SOURCE

替换以下内容:

  • DATASET_NAME:包含 Iceberg 表的数据集。
  • TABLE_NAME:您要将数据加载到的 Iceberg 表的名称。
  • PATH_TO_SOURCE:完全限定的 Cloud Storage URI 或以英文逗号分隔的 URI 列表。通配符也受支持。 例如 gs://mybucket/mydata*.parquet

从平面文件标准加载数据

Iceberg 表使用 BigQuery 加载作业将外部文件加载到 Iceberg 表中。如果您已有 Iceberg 表,请按照 bq load CLI 指南LOAD SQL 指南加载外部数据。加载数据后,新的 Parquet 文件会写入 STORAGE_URI/data 文件夹。

如果使用上述说明时还没有 Iceberg 表,则改为创建 BigQuery 表。

如需查看将数据批量加载到托管式表的工具特定示例,请参阅以下内容:

SQL

LOAD DATA INTO MANAGED_TABLE_NAME
FROM FILES (
uris=['STORAGE_URI'],
format='FILE_FORMAT');

替换以下内容:

  • MANAGED_TABLE_NAME:现有 Iceberg 表的名称。
  • STORAGE_URI:完全限定的 Cloud Storage URI 或以英文逗号分隔的 URI 列表。通配符也受支持。 例如 gs://mybucket/table
  • FILE_FORMAT:源表格式。如需了解支持的格式,请参阅 load_option_listformat 行。

bq

bq load \
  --source_format=FILE_FORMAT \
  MANAGED_TABLE \
  STORAGE_URI

替换以下内容:

  • FILE_FORMAT:源表格式。如需了解支持的格式,请参阅 load_option_listformat 行。
  • MANAGED_TABLE_NAME:现有 Iceberg 表的名称。
  • STORAGE_URI:完全限定的 Cloud Storage URI 或以英文逗号分隔的 URI 列表。通配符也受支持。 例如 gs://mybucket/table

从 Hive 分区文件标准加载数据

您可以使用标准 BigQuery 加载作业将 Hive 分区文件加载到 Iceberg 表中。如需了解详情,请参阅加载外部分区数据

从 Pub/Sub 加载流式数据

您可以使用 Pub/Sub BigQuery 订阅将流式数据加载到 Iceberg 表中。

从 Iceberg 表中导出数据

以下部分介绍了如何将 Iceberg 表中的数据导出为各种表格式。

将数据导出为平面格式

如需将 Iceberg 表导出为平面格式,请使用 EXPORT DATA 语句并选择目标格式。如需了解详情,请参阅导出数据

创建 Iceberg 表元数据快照

如需创建 Iceberg 表元数据快照,请按照以下步骤操作:

  1. 使用 EXPORT TABLE METADATA SQL 语句将元数据导出为 Iceberg 格式。

  2. 可选:安排 Iceberg 元数据快照刷新。如需根据设定的时间间隔刷新 Iceberg 元数据快照,请使用预定查询

以下示例会使用 DDL 语句 EXPORT TABLE METADATA FROM mydataset.test 创建名为 My Scheduled Snapshot Refresh Query 的预定查询。目标数据集为 mydataset。DDL 语句每 24 小时运行一次。

bq query \
    --use_legacy_sql=false \
    --destination_dataset=mydataset
    --display_name='My Scheduled Snapshot Refresh Query' \
    --schedule='every 24 hours' \
    'EXPORT TABLE METADATA FROM mydataset.test'

查看 Iceberg 表元数据快照

刷新 Iceberg 表元数据快照后,您可以在 Iceberg 表最初创建时使用的 Cloud Storage URI 中找到该快照。/data 文件夹包含 Parquet 文件数据分片,/metadata 文件夹包含 Iceberg 表元数据快照。

SELECT
  table_name,
  REGEXP_EXTRACT(ddl, r"storage_uri\s*=\s*\"([^\"]+)\"") AS storage_uri
FROM
  `mydataset`.INFORMATION_SCHEMA.TABLES;

请注意,mydatasettable_name 是实际数据集和表的占位项。

使用 Apache Spark 读取 Iceberg 表

使用 HadoopCatalog 在 Apache Spark 中设置和读取表数据。

以下示例会将您的环境设置为搭配使用 Spark SQL 与 Apache Iceberg,然后执行查询以从指定的 Iceberg 表中提取数据。

spark-sql \
  --packages org.apache.iceberg:iceberg-spark-runtime-ICEBERG_VERSION_NUMBER \
  --conf spark.sql.catalog.CATALOG_NAME=org.apache.iceberg.spark.SparkCatalog \
  --conf spark.sql.catalog.CATALOG_NAME.type=hadoop \
  --conf spark.sql.catalog.CATALOG_NAME.warehouse='BUCKET_PATH' \

# Query the table
SELECT * FROM CATALOG_NAME.FOLDER_NAME;

替换以下内容:

  • ICEBERG_VERSION_NUMBER:Apache Spark Iceberg 运行时的当前版本。从 Spark 版本下载最新版本。
  • CATALOG_NAME:用于引用 Iceberg 表的目录。
  • BUCKET_PATH:包含表文件的存储桶的路径。例如 gs://mybucket/
  • FOLDER_NAME:包含表文件的文件夹。例如 myfolder

修改 Iceberg 表

如需修改 Iceberg 表,请按照修改表架构中所示的步骤操作。

价格

Iceberg 表价格由三个单独的部分组成:

存储

Iceberg 表将所有数据存储在 Cloud Storage 中。您需要为所有存储的数据付费,包括历史表数据。您还可能需要支付 Cloud Storage 数据处理转移费用(如适用)。无需支付 BigQuery 特定的存储费用。如需了解详情,请参阅 Cloud Storage 价格

存储优化

Iceberg 表需要存储优化操作,例如文件合并和重新聚簇。这些优化操作使用企业版随用随付型槽,而不是使用现有的 BACKGROUND 预留。

通过 BigQuery Storage Write API 进行流式传输时发生的数据导出操作包含在 Storage Write API 价格中,不会作为后台维护计费。如需了解详情,请参阅数据注入价格

您可以在 INFORMATION_SCHEMA.JOBS 视图中查看存储优化用量。

查询和作业

与 BigQuery 表类似,如果您使用 BigQuery 按需价格,则需要为查询和读取的字节(每 TiB)付费;如果您使用 BigQuery 容量计算价格,则需要为槽使用量(每个槽每小时)付费。

BigQuery 价格也适用于 BigQuery Storage Read APIBigQuery Storage Write API

加载和导出操作(例如 EXPORT METADATA)使用企业版随用随付型槽。这与 BigQuery 表不同,后者不会针对这些操作计费。如果提供了具有企业版或企业 Plus 版槽的 PIPELINE 预留,则加载和导出操作会优先改为使用这些预留槽。

限制

Iceberg 表存在以下限制: