通過Spark SQL讀寫Iceberg外表

更新時間:
Copy as MD

AnalyticDB for MySQL支援通過Spark SQL建立、讀寫和管理Iceberg外表。Spark 3.5及以上版本預設內建Iceberg讀寫能力,無需額外配置即可使用。本文介紹如何選擇Catalog模式管理Iceberg表中繼資料,以及如何完成Iceberg外表的建立、讀寫、查詢和刪除操作。

前提條件

Catalog模式說明

Spark讀寫Iceberg外表時,需要通過Catalog管理表的中繼資料。AnalyticDB for MySQL支援以下三種Catalog模式:

Catalog模式

說明

是否需要額外配置

適用情境

MDS Catalog(預設)

基於AnalyticDB for MySQL內建中繼資料服務(MDS)管理Iceberg表中繼資料。

不需要,開箱即用。

僅在AnalyticDB for MySQL內部使用Spark讀寫Iceberg表。

Hadoop Catalog

基於Hadoop檔案系統管理Iceberg表中繼資料,中繼資料以檔案形式儲存在指定的OSS路徑下。

需要配置spark.iceberg.warehouse

需要跨產品協同讀寫同一張表,例如EMR Spark、Flink等。

湖儲存

基於AnalyticDB for MySQL湖儲存管理Iceberg表,底層使用Hadoop Catalog,由系統自動管理儲存路徑。

需要開啟spark.adb.lakehouse.enabled

湖倉版叢集使用湖儲存功能。

如何選擇Catalog模式

  • 僅在AnalyticDB for MySQL內部使用:三種模式均可,推薦使用湖儲存模式(若已開通湖儲存)或預設的MDS Catalog模式,配置最簡單。

  • 需要跨產品協同讀寫同一張表(例如EMR Spark寫入後由AnalyticDB for MySQL查詢,或Flink寫入後由Spark查詢):建議使用Hadoop Catalog或湖儲存模式。不同Catalog模式的中繼資料相互獨立,跨模式混合寫入同一張表會導致中繼資料不一致,詳情請參見注意事項

表名引用方式

AnalyticDB for MySQL支援以下兩種方式引用Iceberg表:

  • 兩層結構(推薦)資料庫名.表名,例如my_db.my_table。系統會自動識別表類型並路由到對應的Iceberg Catalog,無需指定Catalog名稱。

  • 三層結構Catalog名.資料庫名.表名,例如iceberg.my_db.my_table。適用於需要明確指定Catalog的情境。

Spark 3.5及以上版本中,系統自動註冊了以下Iceberg Catalog名稱:

Catalog名稱

說明

adb_lakehouse_prod

預設的Iceberg Catalog名稱。

iceberg

Iceberg Catalog的簡便別名,與adb_lakehouse_prod等價。

樣本(以下三種寫法等價

SELECT * FROM my_db.my_table;
SELECT * FROM iceberg.my_db.my_table;
SELECT * FROM adb_lakehouse_prod.my_db.my_table;

操作步驟

步驟一:進入資料開發

  1. 登入雲原生資料倉儲AnalyticDB MySQL控制台,在左上方選擇叢集所在地區。在左側導覽列,單擊集群清單,然後單擊目的地組群ID。

  2. 配置Spark參數。

    根據所選的Catalog模式,需要配置不同模式的SET參數:

    Catalog模式

    SET參數

    MDS Catalog(預設)

    SET spark.adb.version=3.5;

    Hadoop Catalog

    SET spark.adb.version=3.5;
    SET spark.iceberg.warehouse=oss://testBucketName/iceberg/;

    湖儲存

    SET spark.adb.lakehouse.enabled=true;

    SET參數的配置方式因資源群組類型而異:

    • Job型資源群組 :直接將SET語句寫在SQL語句前面即可。如本文後續SQL樣本所示。

    • Interactive型資源群組 :需要將Spark參數預先配置到資源群組中。配置完成後,SQL語句中無需再添加對應的SET語句。

      1. 在左側導覽列單擊集群管理 > 資源管理

      2. 在目標資源群組所在行操作列,單擊修改

      3. 修改資源組面板中更新Spark 配置,然後單擊確定

        當資源群組狀態變為運行中時,修改生效。

  3. 在左側導覽列,單擊作業開發 > SQL開發

  4. SQLConsole視窗,選擇Spark引擎和資源群組(Job型資源群組或Spark引擎的Interactive型資源群組)。

步驟二:建立外庫與Iceberg外表

請根據所選的Catalog模式,按照對應方式建立外庫和Iceberg外表。

MDS Catalog模式(預設)

Spark 3.5及以上版本預設內建Iceberg Catalog支援。MDS Catalog模式下,中繼資料由AnalyticDB for MySQL MDS自動管理,無需配置spark.iceberg.warehouseCatalog參數,但需要指定資料的儲存位置(LOCATION)。

  1. 建立外庫

    • 您可以在建立資料庫時通過LOCATION指定預設的資料存放區路徑。指定後,該資料庫下所有表將自動繼承此路徑。

      SET spark.adb.version=3.5;
      
      CREATE DATABASE adb_iceberg_db LOCATION 'oss://your-bucket/iceberg/';
    • 您也可以建立不帶LOCATION的資料庫。此時需要在建表時為每張表單獨指定LOCATION

      CREATE DATABASE adb_iceberg_db;
  2. 建立Iceberg外表

    SET spark.adb.version=3.5;
    
    -- 若資料庫已指定LOCATION,建表時無需再指定
    CREATE TABLE adb_iceberg_db.test_iceberg_tbl (
      `id` int,
      `name` string,
      `age` int
    ) USING iceberg
    PARTITIONED BY (age);
    
    -- 若資料庫未指定LOCATION,建表時需通過LOCATION指定資料存放區路徑
    CREATE TABLE adb_iceberg_db.test_iceberg_tbl (
      `id` int,
      `name` string,
      `age` int
    ) USING iceberg
    PARTITIONED BY (age)
    LOCATION 'oss://your-bucket/iceberg/test_iceberg_tbl';

Hadoop Catalog模式

如需與其他引擎或產品(如EMR Spark、Flink等)共同讀寫同一張Iceberg表,建議使用Hadoop Catalog模式並指定OSS warehouse路徑,具體配置請參見SET參數配置

  1. 建立外庫前的檢查

    如需使用已有資料庫,請通過DESCRIBE DATABASE查看資料庫DDL,確認滿足以下條件之一:

    • DDL中未指定Location

    • DDL中指定了Location,且Catalog參數值為mix

    如不滿足上述條件,請建立資料庫。

  2. 建立外庫

    CREATE DATABASE adb_external_db_iceberg;
    重要

    如果資料庫指定了Location,請確保spark.iceberg.warehouse參數指定的OSS路徑首碼與Location保持一致。

  3. 建立Iceberg外表

    SET spark.adb.version=3.5;                                  -- 指定Spark引擎大版本
    SET spark.iceberg.warehouse=oss://testBucketName/iceberg/;   -- Iceberg外表中繼資料與資料檔案的儲存路徑
    
    CREATE TABLE adb_external_db_iceberg.test_iceberg_tbl (
      `id` int,
      `name` string,
      `age` int
    ) USING iceberg
    PARTITIONED BY (age);

湖儲存模式

湖倉版叢集支援通過湖儲存模式建立和管理Iceberg表。湖儲存模式底層使用Hadoop Catalog,由AnalyticDB for MySQL自動管理資料存放區路徑。

  1. 建立外庫

    CREATE DATABASE adb_external_db_iceberg
      WITH DBPROPERTIES (
        'adb_lake_bucket' = 'adb-lake-cn-shanghai-6gml****'
      );

    adb_lake_bucket:非必須。指定湖儲存表資料的儲存位置。在資料庫層級指定後,該資料庫下所有表預設使用此湖儲存空間。您也可以在建表時單獨指定,表層級配置優先於資料庫層級。

  2. 建立Iceberg外表

    SET spark.adb.lakehouse.enabled=true;                       -- 開啟湖儲存
    
    CREATE TABLE adb_external_db_iceberg.test_iceberg_tbl (
      `id` int,
      `name` string,
      `age` int
    ) USING iceberg
    PARTITIONED BY (age)
    TBLPROPERTIES (
      'adb_lake_bucket' = 'adb-lake-cn-shanghai-6gml****'
    );

步驟三:寫入或刪除Iceberg外表資料

以下樣本以MDS Catalog模式為主進行說明。

寫入資料

  • INSERT INTO(追加寫入)

    SET spark.adb.version=3.5;
    
    INSERT INTO adb_iceberg_db.test_iceberg_tbl
    VALUES (1, 'lisa', 10), (2, 'jams', 20);
  • INSERT OVERWRITE(全量覆蓋寫入)

    INSERT OVERWRITE adb_iceberg_db.test_iceberg_tbl
    VALUES (1, 'lisa', 10), (2, 'jams', 30);
  • INSERT OVERWRITE靜態分區寫入

    僅覆蓋指定分區的資料,其他分區不受影響。

    INSERT OVERWRITE adb_iceberg_db.test_iceberg_tbl
      PARTITION(age=10)
    VALUES (1, 'anna');
  • INSERT OVERWRITE動態分區寫入

    僅覆蓋寫入資料所涉及的分區,其他分區不受影響。

    重要

    如未設定spark.sql.sources.partitionOverwriteMode=dynamic,INSERT OVERWRITE將覆蓋全表資料,而非僅覆蓋目標資料分割。

    SET spark.sql.sources.partitionOverwriteMode=dynamic;        -- 開啟動態分區覆蓋模式
    
    INSERT OVERWRITE adb_iceberg_db.test_iceberg_tbl
      PARTITION(age)
    VALUES (1, 'bom', 10);
  • UPDATE(條件更新)

    UPDATE adb_iceberg_db.test_iceberg_tbl
    SET name = 'box'
    WHERE id = 2;

刪除資料

DELETE FROM adb_iceberg_db.test_iceberg_tbl
WHERE id = 1;

DELETE FROM adb_iceberg_db.test_iceberg_tbl
WHERE age = 20;

步驟四:查詢Iceberg外表資料

SET spark.adb.version=3.5;

SELECT * FROM adb_iceberg_db.test_iceberg_tbl;

返回樣本

+---+----+---+
|id |name|age|
+---+----+---+
|2  |box|30 |
+---+----+---+

步驟五:刪除Iceberg外表

MDS Catalog模式

SET spark.adb.version=3.5;

-- 僅刪除表的中繼資料,不刪除底層資料檔案
DROP TABLE adb_iceberg_db.test_iceberg_tbl;

-- 同時刪除表的中繼資料和底層資料檔案
DROP TABLE adb_iceberg_db.test_iceberg_tbl PURGE;

Hadoop Catalog模式

SET spark.adb.version=3.5;

DROP TABLE adb_iceberg_db.test_iceberg_tbl;

湖儲存模式

SET spark.adb.lakehouse.enabled=true;

DROP TABLE adb_external_db_iceberg.test_iceberg_tbl;
說明

湖儲存模式下,DROP TABLE僅刪除表的中繼資料,不支援通過PURGE關鍵字刪除底層資料檔案,資料會由AnalyticDB for MySQL表資源回收筒延遲刪除。

進階功能:中繼資料查詢與預存程序

Iceberg提供了中繼資料表查詢和預存程序(Procedure)能力,用於表維護和中繼資料分析。

說明

中繼資料表查詢和預存程序的調用與普通讀寫遵循相同的Catalog配置規則。使用兩層結構(db.table)時,系統會自動路由到對應Catalog,無需額外配置;使用三層結構時需指定Catalog名稱。對於通過Hadoop Catalog或湖儲存模式建立的表,還需配置對應的SET參數(如spark.iceberg.warehousespark.adb.lakehouse.enabled)。

查詢中繼資料表

Iceberg為每張表自動維護了多種中繼資料表,您可以通過表名.中繼資料表名的方式進行查詢。

SET spark.adb.version=3.5;

-- 查看錶的快照資訊(快照ID、時間戳記、操作類型等)
SELECT * FROM adb_iceberg_db.test_iceberg_tbl.snapshots;

-- 查看錶的變更歷史
SELECT * FROM adb_iceberg_db.test_iceberg_tbl.history;

-- 查看當前快照中的資料檔案資訊
SELECT * FROM adb_iceberg_db.test_iceberg_tbl.files;

-- 查看manifest條目(每個檔案的詳細引用資訊)
SELECT * FROM adb_iceberg_db.test_iceberg_tbl.entries;

-- 查看分區統計資訊(記錄數、檔案數等)
SELECT * FROM adb_iceberg_db.test_iceberg_tbl.partitions;

常用的中繼資料表包括snapshotshistoryfilesmanifestsentriespartitionsrefs等。此外,以all_為首碼的中繼資料表(如all_data_filesall_manifestsall_entries)可查看包含歷史快照在內的全量資訊。完整列表請參見Apache Iceberg官方文檔

使用預存程序(Procedure)

您可以通過CALL語句調用預存程序進行表維護。

-- 兩層結構:直接使用system命名空間
CALL system.procedure_name('資料庫名.表名', 其他參數...);

-- 三層結構:需加上Catalog名首碼
CALL iceberg.system.procedure_name('資料庫名.表名', 其他參數...);

以下是常用的表維護操作樣本。

  • 合并小檔案(rewrite_data_files)

    SET spark.adb.version=3.5;
    
    -- 使用預設binpack策略合并小檔案
    CALL system.rewrite_data_files('adb_iceberg_db.test_iceberg_tbl');
    
    -- 使用sort策略並指定排序欄位,僅對指定分區生效
    CALL system.rewrite_data_files(
      table => 'adb_iceberg_db.test_iceberg_tbl',
      strategy => 'sort',
      sort_order => 'id ASC NULLS FIRST',
      where => 'age = 10'
    );
  • 最佳化manifest檔案(rewrite_manifests)

    CALL system.rewrite_manifests('adb_iceberg_db.test_iceberg_tbl');
  • 到期快照清理(expire_snapshots)

    CALL system.expire_snapshots(
      table => 'adb_iceberg_db.test_iceberg_tbl',
      older_than => TIMESTAMP '2024-01-01 00:00:00',
      retain_last => 5
    );
  • 快照復原(rollback_to_snapshot)

    -- 先查詢快照列表擷取目標snapshot_id
    SELECT * FROM adb_iceberg_db.test_iceberg_tbl.snapshots;
    
    -- 復原到指定快照
    CALL system.rollback_to_snapshot('adb_iceberg_db.test_iceberg_tbl', 1234567890);

除上述預存程序外,還支援remove_orphan_files(清理孤立檔案)和rollback_to_timestamp(按時間復原)等操作。完整列表請參見Apache Iceberg官方文檔

AnalyticDB for MySQL增強預存程序

AnalyticDB for MySQL在標準Iceberg預存程序基礎上,額外提供了資料歸檔和生命週期管理能力。

  • 資料歸檔(archive_files)

    將冷資料歸檔到低成本儲存類型,降低儲存費用。

    -- 歸檔30天前的資料到Archive儲存(dry_run=true表示僅預覽影響範圍,不實際執行)
    CALL system.archive_files(
      table => 'adb_iceberg_db.test_iceberg_tbl',
      storage_type => 'Archive',
      start_days => 30,
      dry_run => true
    );
  • 檢查歸檔狀態(check_archive_status)

    查看各儲存類型下的檔案分布情況。

    CALL system.check_archive_status(
      table => 'adb_iceberg_db.test_iceberg_tbl',
      group_by_partition => true
    );
  • 資料解凍(restore_files)

    將已歸檔的資料恢複到標準儲存類型。

    CALL system.restore_files(
      table => 'adb_iceberg_db.test_iceberg_tbl',
      where => 'age = 10'
    );
  • 分區生命週期管理(ttl)

    基於分區的最後更新時間,識別或刪除到期分區。

    -- 查看超過90天未更新的分區(dry_run=true表示僅預覽,不執行刪除)
    CALL system.ttl(
      table => 'adb_iceberg_db.test_iceberg_tbl',
      expire_after_days => 90,
      dry_run => true
    );

注意事項

不同Catalog模式的中繼資料一致性

三種Catalog模式各自獨立管理Iceberg表的中繼資料。在AnalyticDB for MySQL內部,MDS Catalog能夠感知通過Hadoop Catalog或湖儲存模式建立的表,因此在不添加額外配置的情況下也可以讀取這些表。但這不意味著可以跨模式混合寫入。

Catalog模式之間的跨模式讀寫行為

表的建立模式

通過MDS Catalog(預設)

通過Hadoop Catalog

通過湖儲存

MDS Catalog建立的表

讀寫正常

無法識別

無法識別

Hadoop Catalog建立的表

可讀取,不建議寫入

讀寫正常

不建議混用

湖儲存建立的表

可讀取,不建議寫入

可讀寫,但無法自動管理路徑

讀寫正常

重要

請勿跨Catalog模式混合寫入同一張表。雖然MDS Catalog可以讀取Hadoop Catalog和湖儲存模式建立的表,但如果通過MDS Catalog寫入這些表,更新的中繼資料僅會記錄在MDS中,不會同步到Hadoop Catalog的檔案系統中繼資料。這將導致其他引擎讀取到的資料與實際資料不一致。

建議對同一張表,始終使用建立該表時所用的Catalog模式進行讀寫操作。如需跨產品協同,請在建表時選擇Hadoop Catalog或湖儲存模式。

運行環境配置

  • 使用Iceberg相關功能時,Spark版本需為3.5及以上。如果叢集預設Spark版本不是3.5,請在SQL語句開頭添加SET spark.adb.version=3.5;

  • 根據所選的Catalog模式,需要配置不同模式的SET參數,不同資源群組的配置方式,請參見SET參數配置

批處理與互動式模式

Spark SQL支援批處理和互動式兩種運行模式。請確認所使用的資源群組類型與運行模式相匹配。