AnalyticDB for MySQL的XIHE引擎原生支援Apache Iceberg湖表格式。您可以通過標準SQL建立Iceberg表,並執行資料寫入和查詢操作。本文介紹Iceberg外表(XIHE SQL)的方法。
前提條件
叢集的產品系列為企業版、基礎版或湖倉版。
叢集的核心版本為3.2.3.0及以上版本。
已建立外部資料庫。建立方法請參見CREATE EXTERNAL DATABASE。
如需使用內湖模式(AnalyticDB託管湖儲存),需提交工單開通湖儲存功能。詳情請參見湖儲存。
背景資訊
Apache Iceberg是一種開放的資料湖表格式,支援ACID事務、分區裁剪等特性。資料以Parquet格式儲存在OSS上,任何相容Iceberg的計算引擎均可直接讀取。
AnalyticDB支援兩種儲存模式,在建表時一次性確定,建表後不可變更:
維度 | 內湖(託管湖儲存) | 外湖(使用者自有OSS) |
儲存管理 | AnalyticDB全託管 | 使用者自管理OSS Bucket |
建表關鍵參數 |
|
|
開通方式 | 需提交工單申請開通 | 同帳號下無需額外操作 |
適用情境 | 新專案,希望簡化營運 | 已有OSS資料,或需要自主管理儲存 |
建表
文法
CREATE TABLE [IF NOT EXISTS] <db>.<table> (
<col1> <type1> [COMMENT '<comment>'],
<col2> <type2> [COMMENT '<comment>'],
...
)
[COMMENT '<table_comment>']
[PARTITIONED BY (<partition_expr1>[, <partition_expr2>, ...])]
STORED AS ICEBERG
[LOCATION '<oss_path>'] -- 外湖必填
[TBLPROPERTIES (
'format-version' = '<2|3>', -- 預設2
'catalog_type' = 'ADB', -- 內湖必填
'adb_lake_bucket' = '<bucket_name>', -- 內湖必填
...
)];子句 | 是否必填 | 說明 |
| 是 | 聲明表格式為Iceberg。 |
| 否 | 分區運算式。支援identity分區(直接使用列值)和轉換函式分區( |
| 外湖必填 | 指向使用者自有OSS路徑,格式為 |
| 內湖必填 | 內湖模式需包含 |
TBLPROPERTIES中可配置的表屬性如下:
屬性 | 預設值 | 說明 |
| 無 | 內湖必填,取值為 |
| 無 | 內湖必填,取值為AnalyticDB分配的OSS Bucket名。 |
|
| Iceberg Format Version,支援 |
| 無 | 外湖模式下,如需指向已有Iceberg資料,需填寫 |
外湖建表示例
-- 建立資料庫
CREATE DATABASE IF NOT EXISTS lake_db;
-- 建立外湖Iceberg表
CREATE TABLE lake_db.orders (
order_id BIGINT COMMENT '訂單ID',
user_id BIGINT COMMENT '使用者ID',
status STRING COMMENT '訂單狀態',
total_amount DECIMAL(18, 2) COMMENT '訂單金額',
created_at TIMESTAMP COMMENT '下單時間'
)
COMMENT '訂單主表'
PARTITIONED BY (dt DATE)
STORED AS ICEBERG
LOCATION 'oss://<YOUR-BUCKET>/warehouse/lake_db/orders/';外湖建表通過LOCATION指定路徑,不寫catalog_type。LOCATION路徑建議以/<database>/<table>/結尾,例如oss://<YOUR-BUCKET>/warehouse/lake_db/orders/。
內湖建表示例
CREATE TABLE lake_db.orders (
order_id BIGINT COMMENT '訂單ID',
user_id BIGINT COMMENT '使用者ID',
status STRING COMMENT '訂單狀態',
total_amount DECIMAL(18, 2) COMMENT '訂單金額',
created_at TIMESTAMP COMMENT '下單時間'
)
COMMENT '訂單主表'
PARTITIONED BY (dt DATE)
STORED AS ICEBERG
TBLPROPERTIES (
'catalog_type' = 'ADB',
'adb_lake_bucket' = 'adb-lake-cn-<region>-xxxx'
);內湖建表不寫LOCATION,儲存路徑由AnalyticDB自動分配。使用內湖模式前需先開通湖儲存功能,adb_lake_bucket的值請參見建立資料湖表。
CTAS建表(CREATE TABLE AS SELECT)
CTAS在建表的同時寫入查詢結果,列名和類型從SELECT推導。
CREATE TABLE lake_db.orders_copy
PARTITIONED BY (dt DATE)
STORED AS ICEBERG
LOCATION 'oss://<YOUR-BUCKET>/warehouse/lake_db/orders_copy/'
AS SELECT * FROM lake_db.orders;分區管理
Iceberg的分區與傳統Hive分區有本質區別:
維度 | Hive分區 | Iceberg分區 |
分區是否為列 | 分區列是獨立列 | 分區可以基於現有列的轉換(如 |
寫入時需感知分區 | INSERT必須指定分區值 | INSERT不需要顯式寫分區值,引擎自動路由 |
查詢時需感知分區 | 必須WHERE帶分區列 | 引擎自動進行分區裁剪 |
Iceberg支援identity分區(直接使用列值)和基於現有列的轉換函式分區。寫入時無需指定分區值,引擎根據列值自動路由。
函數 | 適用類型 | 樣本 |
identity | 任意 |
|
| DATE / TIMESTAMP |
|
| DATE / TIMESTAMP |
|
| DATE / TIMESTAMP |
|
| TIMESTAMP |
|
分區轉換不是獨立列:day(created_at)不會建立新列,Iceberg在Manifest檔案中記錄轉換後的分區值。分區過多會影響效能,高基數列建議使用day()或month()控制分區數。
使用day(created_at)分區時,無需單獨維護dt列,Iceberg自動從created_at提取日期做分區:
CREATE TABLE lake_db.orders_by_day (
order_id BIGINT,
user_id BIGINT,
status STRING,
total_amount DECIMAL(18, 2),
created_at TIMESTAMP
)
PARTITIONED BY (day(created_at))
STORED AS ICEBERG
LOCATION 'oss://<YOUR-BUCKET>/warehouse/lake_db/orders_by_day/';其他DDL操作
-- 查看錶的完整建表語句
SHOW CREATE TABLE lake_db.orders;
-- 查看列結構
DESCRIBE lake_db.orders;
-- 刪除表
DROP TABLE IF EXISTS lake_db.orders;
-- 刪除資料庫(庫內不能有表,否則報錯)
DROP DATABASE IF EXISTS lake_db;對內湖表執行DROP TABLE會同時刪除OSS上的資料檔案和中繼資料,操作無法復原。外湖表的DROP TABLE僅刪除AnalyticDB中的表定義,OSS上的資料檔案不受影響。
寫入資料
INSERT INTO(追加寫入)
INSERT INTO lake_db.orders
SELECT * FROM VALUES
(1001, 501, 'paid', 299.90, TIMESTAMP '2026-06-11 10:00:00', DATE '2026-06-11'),
(1002, 502, 'pending', 158.00, TIMESTAMP '2026-06-11 10:05:00', DATE '2026-06-11'),
(1003, 503, 'shipped', 450.00, TIMESTAMP '2026-06-11 10:10:00', DATE '2026-06-12')
AS t(order_id, user_id, status, total_amount, created_at, dt);核心版本3.2.8之前,INSERT文法必須使用INSERT INTO ... SELECT * FROM VALUES (...) AS t(...)形式。3.2.8及以上版本支援INSERT INTO ... VALUES (...)直接寫法。
INSERT OVERWRITE(覆寫)
對分區表執行INSERT OVERWRITE時,Iceberg採用動態分區覆寫策略——僅覆蓋SELECT結果中涉及的分區,其餘分區資料不受影響。
-- 僅覆蓋dt='2026-06-11'分區的資料,其他分區不受影響
INSERT OVERWRITE lake_db.orders
SELECT * FROM VALUES
(2001, 601, 'paid', 999.00, TIMESTAMP '2026-06-11 12:00:00', DATE '2026-06-11')
AS t(order_id, user_id, status, total_amount, created_at, dt);DELETE(行級刪除)
Iceberg表支援基於條件的行級刪除。
DELETE FROM lake_db.orders WHERE status = 'cancelled';查詢資料
基本查詢
SELECT * FROM lake_db.orders WHERE dt = DATE '2026-06-11';
SELECT dt, COUNT(*) AS cnt, SUM(total_amount) AS total
FROM lake_db.orders
GROUP BY dt;分區裁剪
當WHERE條件中包含分區列或分區轉換函式時,引擎自動進行分區裁剪,只掃描相關分區的資料檔案。
-- identity分區:直接匹配分區列
SELECT * FROM lake_db.orders WHERE dt = DATE '2026-06-11';
-- day(col)分區:匹配時間範圍
SELECT * FROM lake_db.orders_by_day
WHERE created_at >= TIMESTAMP '2026-06-11 00:00:00'
AND created_at < TIMESTAMP '2026-06-12 00:00:00';謂詞下推
Iceberg將WHERE條件中的謂詞下推到資料檔案層面,利用Parquet檔案內部的統計資訊(min/max/null count)過濾不滿足條件的row group,減少實際讀取的資料量。
謂詞下推生效條件:
WHERE條件中的列存在統計資訊。
謂詞為簡單比較(
=、<、>、<=、>=、IN、BETWEEN)。列類型與統計資訊類型匹配。
-- 謂詞下推生效:order_id有min/max統計資訊
SELECT * FROM lake_db.orders
WHERE order_id = 1001;
-- 範圍謂詞下推
SELECT * FROM lake_db.orders
WHERE total_amount BETWEEN 100 AND 500;查詢注意事項
分區裁剪僅對WHERE條件中直接引用分區列或分區轉換函式的情境生效。
複雜謂詞(如函數調用、OR條件)可能影響謂詞下推效果。
跨Iceberg表JOIN效能取決於資料量和分區設計。
可選配置項
以下配置項可通過Config或Hint方式設定,用於調整Iceberg表的寫入和查詢行為。
配置名稱 | 說明 | 是否需要重啟 |
| 寫入時每個Writer允許的最大分區數。預設值100。 | 否 |
| 中繼資料快取開關。預設值true。 | 否 |
| 查詢時Manifest緩衝策略。取值: | 否 |
以下為執行個體級配置,修改後需要重啟執行個體生效:
配置名稱 | 說明 | 預設值 |
| Manifest檔案快取總開關。 | false |
| Manifest緩衝最大總位元組數。 | 104857600(100 MB) |
| 緩衝條目到期時間(毫秒)。 | 0(永不到期) |
| 單個Manifest檔案可快取的最大位元組數,超過則不緩衝。 | 8388608(8 MB) |
使用限制
字串類型統一使用
STRING,不支援VARCHAR或CHAR(N)。STORED AS ICEBERG是必需子句,缺失時不會建立Iceberg表。核心版本3.2.8之前,INSERT文法必須使用
INSERT INTO t SELECT * FROM VALUES (...)形式。3.2.8及以上版本支援INSERT INTO t VALUES (...)直接寫法。INSERT OVERWRITE對分區表採用動態分區覆寫策略,僅替換SELECT結果中涉及的分區。
儲存模式(內湖/外湖)建表後不可變更。
內湖建表必須同時指定
catalog_type='ADB'和adb_lake_bucket,缺一不可。外湖建表通過LOCATION指定路徑,不寫catalog_type。分區過多會影響效能,高基數列建議使用
day()或month()控制分區數。