借助 AlloyDB for PostgreSQL 中的直接 Iceberg 访问,您可以从 AlloyDB 实例查询 Cloud Storage 中以 Apache Iceberg 表格式存储的数据。您可以使用 Cloud Storage 存储桶 URI 或 Lakehouse 运行时目录访问 Iceberg 数据集。为了加速分析工作负载,AlloyDB 提供了一个内置的列式引擎,可优化扫描、联接和聚合。通过与列式引擎集成,直接 Iceberg 访问可让您在数据湖仓一体上运行高性能分析查询,而无需构建、管理或维护复杂的提取、转换和加载 (ETL) 数据流水线。
您可以使用标准 SQL 命令查询 Iceberg 表,将 Iceberg 数据集与 AlloyDB 中的操作表联接,并将 Iceberg 表填充到内存中列式引擎,以提升查询性能。
优势
直接 Iceberg 访问具有以下优势:
- 零 ETL 湖仓一体访问:就地查询外部 Iceberg 数据集,无需将数据复制或移动到单独的分析系统。
- 统一的事务和分析查询:将存储在 AlloyDB 堆表中的实时运营数据与存储在 Cloud Storage 上的 Iceberg 表中的海量历史数据联接起来。
- 灵活的目录集成:通过 Cloud Storage 存储桶路径或 Lakehouse 运行时目录访问 Iceberg 表元数据。
- 列式查询加速:将 Iceberg 表缓存并填充到 AlloyDB 列式引擎内存中,实现亚秒级分析处理。
- 标准 SQL 接口:使用熟悉的 PostgreSQL 语法查询和分析 Iceberg 表。
直接 Iceberg 访问权限的工作原理
直接 Iceberg 访问使用 PostgreSQL 表访问方法 (TAM) 接口 (USING iceberg),并与 AlloyDB 列式引擎规划器和执行框架集成。
查询 Iceberg 表时,AlloyDB 会在以下模式之一中运行:
- 直接扫描(适用于流式读取):AlloyDB 直接从 Cloud Storage 读取最新的元数据和数据文件。列式引擎以流式方式处理数据。
- 列式引擎加速(针对内存缓存的读取):使用
google_columnar_engine_add()函数将 Iceberg 表填充到 AlloyDB 列式引擎中时,该表会加载到内存中的列式存储区中。后续查询会从列式引擎内存中读取,从而最大限度地提高查询吞吐量并最大限度地减少延迟时间。
快照传送和缓存刷新
AlloyDB 查询的 Iceberg 表快照取决于读取模式:
直接扫描:AlloyDB 会针对最新的 Iceberg 快照运行查询。查询开始时,AlloyDB 会确定最新的可用 Iceberg 表快照,并从该快照中读取数据,即使在
REPEATABLE READ或SERIALIZABLE事务中也是如此。AlloyDB 不支持跨事务的快照固定和时间点查询。例如,当您使用直接扫描查询表时,事务中的每个语句都会从最新的可用快照中读取:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; SELECT * FROM customer_orders; -- If an external process commits a new Iceberg snapshot: SELECT * FROM customer_orders; -- Returns results from the new snapshot. COMMIT;列式引擎加速:AlloyDB 会在列式引擎中填充的快照上运行查询。如果 AlloyDB 在填充后将新数据写入 Cloud Storage 中的底层 Iceberg 表,则查询可能会返回过时的数据。如需在对底层表执行 DML 操作后获取最新数据,请使用
google_columnar_engine_refresh()函数刷新缓存。
支持的数据类型
在 AlloyDB 中定义 Iceberg 表时,DDL 语句中的列名称和数据类型必须与底层 Iceberg 架构中的类型匹配。
直接 Iceberg 访问支持以下 Apache Iceberg 数据类型及其对应的 AlloyDB 类型:
| Apache Iceberg 数据类型 | AlloyDB 数据类型 | 说明 |
|---|---|---|
boolean |
BOOLEAN |
向量化转换为字节打包格式 |
int |
INT/INTEGER |
32 位有符号整数 |
long |
BIGINT |
64 位有符号整数 |
float |
REAL/FLOAT4 |
32 位单精度浮点数 |
double |
DOUBLE PRECISION/FLOAT8 |
64 位双精度浮点数 |
decimal(P, S) |
NUMERIC(P, S)/DECIMAL(P, S) |
精度为 P 且标度为 S 的定点数值 |
string |
TEXT/VARCHAR |
UTF-8 字符串值 |
date |
DATE |
日历日期(年、月、日) |
timestamp |
TIMESTAMP |
不带时区的时间戳 |
timestamptz |
TIMESTAMPTZ |
包含时区的时间戳 |
限制
直接 Iceberg 访问具有以下限制:
- PostgreSQL 版本可用性:AlloyDB 支持在 PostgreSQL 18 及更高版本上直接访问 Iceberg。
- 用户权限:只有具有
alloydbsuperuser角色的数据库用户才能创建 Iceberg 表。创建表后,您可以向其他用户授予SELECT权限,以便查询 Iceberg 表。 - 只读操作:AlloyDB 仅支持对 Iceberg 表执行
SELECT查询 (DQL)。它不支持写入操作(INSERT、UPDATE、DELETE、TRUNCATE)。 - Apache Iceberg 规范版本:AlloyDB 不支持 Iceberg v2 删除文件(位置删除和相等性删除)或 Iceberg v3 删除向量。
- 文件格式支持:直接 Iceberg 访问支持 Parquet 数据文件以及 JSON 和 Avro 元数据文件。不支持 ORC 数据文件。
- 快照版本控制:直接扫描查询在最新的 Iceberg 表快照上运行,而列式加速查询在填充的快照上运行。AlloyDB 不支持时间点查询。
- 架构演变:AlloyDB 不支持对 Iceberg 表执行
ALTER TABLE操作。底层 Iceberg 表不得经历过架构迁移。 - 元数据目录支持:Iceberg 直接访问支持直接 Cloud Storage 存储桶路径 (
gs://) 和 Lakehouse 运行时目录路径 (bl://)。对于 Lakehouse 运行时目录,AlloyDB 仅支持最终用户凭据模式。它不支持凭据分发模式或其他 REST 目录。 - 请求者付款存储桶:AlloyDB 不支持使用请求者付款的 Cloud Storage 存储桶。
- 完整填充限制:AlloyDB 不支持对 Iceberg 表进行部分列式填充。表必须适合列式引擎内存或 SSD 空间。
- 填充堆内存:填充包含大型 Parquet 行组的 Iceberg 表可能会超出每个工作器的填充堆内存限制,尤其是在 vCPU 较少的实例上。如需解决此问题,请参阅列式引擎填充堆已满。
准备工作
在创建和查询 Iceberg 表之前,请确保完成以下操作:
- 在 Google Cloud上创建一个运行 PostgreSQL 18 或更高版本的 AlloyDB 集群。如需了解详情,请参阅创建集群。
- 在 Cloud Storage 中托管 Apache Iceberg 表,或在 Lakehouse 运行时目录中注册该表:
- 对于 Cloud Storage 路径,存储桶目录结构必须遵循标准的 Apache Iceberg 布局,其中包含
data/和metadata/子目录,包括元数据 JSON 文件和version-hint.text。如需了解详情,请参阅创建存储桶。 - 对于 Lakehouse 运行时目录,请在最终用户凭证模式下创建并注册 Iceberg 目录。如需了解详情,请参阅设置 Apache Iceberg REST Catalog 端点。
- 对于 Cloud Storage 路径,存储桶目录结构必须遵循标准的 Apache Iceberg 布局,其中包含
- 为具有
alloydbsuperuser角色的用户设置数据库凭据。如需了解详情,请参阅alloydbsuperuser群组角色。
所需的角色
如需使 AlloyDB 能够读取 Iceberg 数据和元数据,您必须向 AlloyDB 集群服务账号授予所需的 IAM 角色:
- Cloud Storage 访问权限:针对包含 Iceberg 数据和元数据的 Cloud Storage 存储桶授予 Storage Object Viewer (
roles/storage.objectViewer) 角色。 - BigLake 访问权限(如果使用 Lakehouse 运行时目录):在托管 BigLake 目录的项目中授予 BigLake Viewer (
roles/biglake.viewer) 角色。
如需查找集群服务账号,请运行 gcloud beta alloydb clusters describe 命令:
gcloud beta alloydb clusters describe CLUSTER_ID --region=REGION_ID替换以下内容:
CLUSTER_ID:AlloyDB 集群 ID。REGION_ID:AlloyDB 集群的位置。例如us-east1。如需查看完整的区域列表,请参阅 AlloyDB 位置。
输出包含 serviceAccountEmail 字段,该字段是此集群的服务账号。在 Google Cloud 控制台中,您可以在集群概览页面上找到服务账号。
如需使用 gcloud CLI 授予 Storage Object Viewer 角色,请运行以下命令:
gcloud storage buckets add-iam-policy-binding \
gs://BUCKET_NAME \
--member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \
--role="roles/storage.objectViewer"如果您使用 Lakehouse 运行时目录,请授予 BigLake Viewer 角色:
gcloud projects add-iam-policy-binding LAKEHOUSE_PROJECT_ID \
--member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \
--role="roles/biglake.viewer"替换以下内容:
BUCKET_NAME:Cloud Storage 存储桶的名称。LAKEHOUSE_PROJECT_ID:托管 Lakehouse 运行时目录的 Google Cloud 项目 ID。SERVICE_ACCOUNT_EMAIL:您在serviceAccountEmail字段中找到的集群服务账号邮箱。
配置数据库标志
如需启用列式引擎和直接 Iceberg 访问,您可以在 AlloyDB 实例上配置数据库标志。在实例上设置以下数据库标志:
| 数据库标志 | 值 | 说明 |
|---|---|---|
google_columnar_engine.enabled |
on |
启用 AlloyDB 列式引擎。 |
google_columnar_engine.enable_iceberg_reads |
on |
启用 Iceberg 直接访问。需要重启实例。 |
google_columnar_engine.memory_size_in_mb |
SIZE_IN_MB | (可选)为列式引擎分配内存。如果您计划在内存中填充 Iceberg 表,建议使用此选项。 |
如需使用 gcloud CLI 配置这些标志,请运行 gcloud alloydb instances update 命令:
gcloud alloydb instances update INSTANCE_ID \
--cluster=CLUSTER_ID \
--region=REGION_ID \
--database-flags=google_columnar_engine.enabled=on,google_columnar_engine.enable_iceberg_reads=on替换以下内容:
INSTANCE_ID:AlloyDB 实例的 ID。CLUSTER_ID:AlloyDB 集群的 ID。REGION_ID:AlloyDB 集群的地区 ID。
在 AlloyDB 中创建 Iceberg 表
如需在 AlloyDB 中公开 Apache Iceberg 数据集,请以具有 alloydbsuperuser 权限的用户身份进行连接。然后,使用 USING iceberg 表访问方法创建表。
CREATE TABLE TABLE_NAME (
COLUMN_NAME DATA_TYPE [, ...]
)
USING iceberg
WITH (
uri = 'LOCATION_URI'
);
替换以下内容:
TABLE_NAME:要在 AlloyDB 中创建的表的名称。COLUMN_NAME和DATA_TYPE:列定义。列名称和类型必须与底层 Iceberg 表的架构匹配。LOCATION_URI:Iceberg 表元数据的位置。请指定以下某种格式:- 直接 Cloud Storage 路径:
gs://BUCKET_NAME/PATH_TO_ICEBERG_TABLE - Lakehouse 运行时目录 URI:
bl://projects/PROJECT_ID/catalogs/CATALOG_NAME/databases/DATABASE_NAME/tables/TABLE_NAME
- 直接 Cloud Storage 路径:
示例
以下示例展示了如何在 AlloyDB 中创建 Iceberg 表。
通过 Cloud Storage 路径创建表
以下示例创建了一个名为 customer_orders 的表,该表由位于 Cloud Storage 存储桶中的 Iceberg 数据集提供支持:
CREATE TABLE customer_orders (
order_id BIGINT,
customer_id INT,
order_status TEXT,
total_amount DOUBLE PRECISION,
order_date DATE,
is_completed BOOLEAN
)
USING iceberg
WITH (
uri = 'gs://my-iceberg-analytics-bucket/datasets/sales/customer_orders'
);
通过 Lakehouse 运行时目录创建表
以下示例创建了一个表,该表引用了由 Lakehouse 运行时目录管理的 Iceberg 表:
CREATE TABLE customer_orders (
order_id BIGINT,
customer_id INT,
order_status TEXT,
total_amount DOUBLE PRECISION,
order_date DATE,
is_completed BOOLEAN
)
USING iceberg
WITH (
uri = 'bl://projects/my-analytics-project/catalogs/sales_catalog/databases/retail_db/tables/customer_orders'
);
查询 Iceberg 数据
在 AlloyDB 中创建表后,您可以使用具有 alloydbsuperuser 权限的标准 SQL SELECT 语句查询该表。(可选)您可以使用 GRANT 语句向没有 alloydbsuperuser 权限的用户授予读取权限。例如 GRANT SELECT ON customer_orders TO normal_user。
查询数据
以下示例展示了如何运行查询:
SELECT
customer_id,
COUNT(order_id) AS total_orders,
SUM(total_amount) AS total_spent
FROM customer_orders
WHERE is_completed = true
AND order_date >= '2026-01-01'
GROUP BY customer_id
ORDER BY total_spent DESC
LIMIT 10;
查询联合 Iceberg 数据和运营数据
您可以将 AlloyDB 中的实时运营数据与 Iceberg 中的历史数据进行整合:
SELECT
c.customer_name,
c.account_tier,
COUNT(o.order_id) AS total_orders,
SUM(o.total_amount) AS historical_spend
FROM customer_orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.is_completed = true
GROUP BY c.customer_name, c.account_tier
ORDER BY historical_spend DESC;
将数据导入本地表
如需在本地 AlloyDB 存储空间中创建 Iceberg 数据的独立可写副本,请执行 CREATE TABLE ... AS SELECT,如以下示例所示:
CREATE TABLE local_customer_orders AS
SELECT * FROM customer_orders
WHERE order_date >= '2026-01-01';
使用列式引擎加速查询
对于需要超低延迟时间的分析工作负载,您可以直接将 Iceberg 表填充到 AlloyDB 列式引擎内存中。
将 Iceberg 表填充到列式存储区
如需将 Iceberg 表的所有列填充到 AlloyDB 列式引擎中,请使用 google_columnar_engine_add() 函数。例如:
SELECT google_columnar_engine_add('customer_orders');
如需仅填充查询使用的特定列,请将以英文逗号分隔的列名称列表作为第二个参数传递。例如:
SELECT google_columnar_engine_add('customer_orders', 'customer_id,order_status');
如需了解详情,请参阅使用 SQL 函数添加列。
刷新填充的数据
如果您将新快照写入底层 Iceberg 数据集,请刷新表以将最新数据重新加载到列式引擎中,以便查询返回最新结果:
SELECT google_columnar_engine_refresh('customer_orders');
从列式存储中移除表
如需从列式存储中移除 Iceberg 表并还原为直接扫描,请执行以下操作:
SELECT google_columnar_engine_drop('customer_orders');
监控和验证查询执行
您可以监控 AlloyDB 如何对 Iceberg 表执行查询,并验证查询是否使用内存中列式引擎。使用系统视图检查缓存填充状态,并使用 EXPLAIN 检查查询执行计划。
验证列式缓存状态
如需验证 Iceberg 表是否已在列式引擎中填充,请查询 g_columnar_relations 系统视图:
SELECT relation_name, status
FROM g_columnar_relations
WHERE relation_name = 'customer_orders';
status 值为 USABLE 表示该表已缓存在列式引擎内存中。
使用 EXPLAIN 检查查询执行计划
如需验证查询是否利用了列式引擎,请使用 EXPLAIN 语句:
EXPLAIN (ANALYZE, COSTS OFF)
SELECT SUM(total_amount)
FROM customer_orders
WHERE is_completed = true;
输出通过表上的 Custom Scan (ColumnarScan) 节点指示列式执行:
Custom Scan (ColumnarScan) on customer_orders
Filter: (is_completed = true)
问题排查
本部分介绍了如何解决在 AlloyDB 中配置和查询 Iceberg 表时的常见问题。
google_columnar_engine.enable_iceberg_reads 标志已停用
原因:直接 Iceberg 访问的数据库标志已停用。
建议的解决方法:在实例中设置数据库标志 google_columnar_engine.enabled=on 和 google_columnar_engine.enable_iceberg_reads=on,然后重启实例。
访问 Cloud Storage 时权限遭拒
原因:AlloyDB 集群服务账号缺少对 Cloud Storage 存储桶的读取权限。
建议的解决方法:向存储桶上的集群服务账号授予 roles/storage.objectViewer 角色。
访问 Lakehouse 运行时目录时权限遭拒
原因:AlloyDB 集群服务账号缺少对 Lakehouse 运行时目录的读取权限。
建议的修复方法:向托管 Lakehouse 运行时目录的 Google Cloud 项目中的集群服务账号授予 roles/biglake.viewer 角色。
列式填充失败
原因:Iceberg 表大小超过了列式引擎中的可用内存和 SSD 空间。
建议的解决方法:使用实例上的 google_columnar_engine.memory_size_in_mb 标志增加分配给列式引擎的内存,或使用 google_columnar_engine.storage_cache_size 标志增加列式引擎存储缓存大小。如需了解详情,请参阅为列式引擎配置存储缓存。
列式引擎填充堆已满
出错提示:
ERROR: Columnar engine population heap is full during population. Set
google_columnar_engine.population_heap_size_in_mb to a bigger value.
原因:填充大型 Parquet 行组所需的内存超出了每个工作器的填充堆限制。
建议的解决方法:减少并行填充工作器的数量,以便填充进程可以使用更大的堆。在填充表的 SQL 会话中,在调用 google_columnar_engine_add() 函数之前,将 google_job_scheduler.max_parallel_workers_per_job 标志设置为 0:
SET google_job_scheduler.max_parallel_workers_per_job = 0;
SELECT google_columnar_engine_add('TABLE_NAME');
将 TABLE_NAME 替换为 AlloyDB 中 Iceberg 表的名称。
后续步骤
- 了解 AlloyDB 列式引擎。
- 了解如何配置列式引擎。
- 选择如何从 AlloyDB 访问 BigQuery 数据。