カタログリンクデータベースを使って外部管理の Iceberg テーブルへの書き込み操作を試してみた #SnowflakeDB

カタログリンクデータベースを使って外部管理の Iceberg テーブルへの書き込み操作を試してみた #SnowflakeDB

2025.07.31

はじめに

2025年7月のアップデートで外部管理の Iceberg テーブルまたはカタログリンクデータベース(Catalog-linked database)への書き込みがサポートされました。

https://docs.snowflake.com/en/release-notes/2025/other/2025-07-18-iceberg-external-writes-cld

この内、カタログリンクデータベースを使用した外部管理の Iceberg テーブルに書き込み操作を試してみましたので記事としました。

アップデートの概要

Snowflake では Iceberg テーブルとしてテーブルを作成しデータレイクに対してクエリする機能を提供しています。
この際 Snowflake では以下のカタログオプションをサポートしています。

  • Snowflake を Iceberg カタログとして使用
  • 外部の Iceberg カタログを使用

Iceberg については以下の記事で丁寧に解説されています。

https://zenn.dev/dataheroes/articles/snowflake-iceberg-introduction

これまでは、外部カタログを使用する Iceberg テーブルは読み取り専用でしたが、今回のアップデートで書き込み操作がサポートされました。

本機能については以下に記載があります。

https://docs.snowflake.com/en/user-guide/tables-iceberg-externally-managed-writes

さらに今回のアップデートでは、「カタログリンクデータベース」という新機能がプレビューとなりました。これは、外部の Iceberg REST カタログに接続された Snowflake データベースとして機能します。

カタログリンクデータベースの主な特徴は以下の通りです。

  • Iceberg テーブルの自動検出と同期
    • これまでは、外部カタログ内の Iceberg テーブルを Snowflake から参照するには、テーブルごとにCREATE ICEBERG TABLEコマンドを実行する必要がありました。カタログリンクデータベースを使用すると、外部カタログと Snowflake が自動的に同期され、外部カタログ内の名前空間と Iceberg テーブルが自動的に検出され、対応するリモートテーブルがカタログリンクデータベースに自動登録されます
  • 書き込み操作のサポート
    • カタログリンクデータベースを通じて、Iceberg テーブルへの書き込み操作の他、スキーマの作成や Iceberg テーブルの作成・削除もサポートされます

https://docs.snowflake.com/en/user-guide/tables-iceberg-catalog-linked-database

ここではカタログリンクデータベースを使用してみます。

前提条件

以下の環境で検証を行いました。

  • 外部カタログ
    • AWS Glue データカタログ
    • Glue データカタログへの Iceberg テーブルの作成は Fivetran で行う

事前準備

以下の記事をベースに Fivetran で Destination に Amazon S3 を設定することで、 AWS Glue データカタログの機能を使用した Apache Iceberg 形式のテーブルを作成しておきます。

https://dev.classmethod.jp/articles/fivetran-s3-datalake-icebergtable-select-from-snowflake/#toc-snowflake--iceberg-

大元のデータソースも上記の記事通りとし、 SQL Server を使用しています。

以下の手順で SQL Server に3つのテーブルを作成しておきました。コマンドの生成にはAIを使用しています。

CREATE DATABASE testdb;
GO

USE testdb;
GO

-- テーブルの作成
CREATE TABLE sampledata (
    id int primary key,
    randomnumber int,
    randomdate date,
    randomstring varchar(100)
);

-- ランダムなデータの挿入
;WITH cte as (
    SELECT TOP (1000) 
        row_number() over (order by (select null)) as rownum
    FROM sys.columns a
    CROSS JOIN sys.columns b
)
INSERT INTO sampledata (id, randomnumber, randomdate, randomstring)
SELECT 
    rownum,
    abs(checksum(newid())) % 1000, -- 0から999までのランダムな数
    dateadd(day, abs(checksum(newid())) % 3650, '2000-01-01'), -- 過去10年間のランダムな日付
    left(convert(varchar(255), newid()), 10) -- ランダムな文字列
FROM cte;
GO

1> SELECT COUNT(*) FROM sampledata;
2> GO

-----------
       1000

1> SELECT TOP 5 * FROM sampledata;
2> GO
id          randomnumber randomdate       randomstring
----------- ------------ ---------------- ----------------------------------------------------------------------------------------------------
          1          318       2001-03-06 77C73A7B-5
          2          364       2007-07-10 000F3FEE-9
          3          116       2005-11-27 6EDE732C-F
          4          372       2006-09-20 E4FE431D-0
          5          455       2001-07-26 56607F58-8

-- Customers テーブルの作成
CREATE TABLE Customers (
    CustomerID INT IDENTITY(1,1) PRIMARY KEY, 
    FirstName NVARCHAR(50) NOT NULL,          
    LastName NVARCHAR(50) NOT NULL,
    Email NVARCHAR(100) UNIQUE,               
    RegistrationDate DATE DEFAULT GETDATE()   
);

-- Orders テーブルの作成
CREATE TABLE Orders (
    OrderID INT IDENTITY(1,1) PRIMARY KEY,
    CustomerID INT NOT NULL,                  
    OrderDate DATE DEFAULT GETDATE(),
    TotalAmount DECIMAL(10, 2) NOT NULL,      

    -- 外部キー制約の追加
    CONSTRAINT FK_Orders_Customers
    FOREIGN KEY (CustomerID)
    REFERENCES Customers(CustomerID)
);

-- Customers テーブルにデータを挿入
INSERT INTO Customers (FirstName, LastName, Email) VALUES
('Taro', 'Yamada', 'taro.yamada@example.com'),
('Hanako', 'Suzuki', 'hanako.suzuki@example.com'),
('Ken', 'Tanaka', 'ken.tanaka@example.com');

-- Orders テーブルにデータを挿入
INSERT INTO Orders (CustomerID, TotalAmount) VALUES
(1, 150.75), -- Taro Yamada の注文
(1, 25.00),  -- Taro Yamada の別の注文
(2, 300.50), -- Hanako Suzuki の注文
(3, 10.20);  -- Ken Tanaka の注文

-- テーブル確認
>SELECT * FROM Customers;
CustomerID  FirstName                                          LastName                                           Email                                                                                                RegistrationDate
----------- -------------------------------------------------- -------------------------------------------------- ---------------------------------------------------------------------------------------------------- ----------------
          1 Taro                                               Yamada                                             taro.yamada@example.com                                                                                    2025-07-30
          2 Hanako                                             Suzuki                                             hanako.suzuki@example.com                                                                                  2025-07-30
          3 Ken                                                Tanaka                                             ken.tanaka@example.com                                                                                     2025-07-30

>SELECT * FROM Orders;
OrderID     CustomerID  OrderDate        TotalAmount
----------- ----------- ---------------- ------------
          1           1       2025-07-30       150.75
          2           1       2025-07-30        25.00
          3           2       2025-07-30       300.50
          4           3       2025-07-30        10.20

Fivetran による同期完了後の S3 は以下の構成となっていました。テーブル名のパス配下にはdatametadataに分かれます。

image

Snowflake 側の作業

カタログリンクデータベースを作成するには、外部カタログやテーブルへのアクセスを構成します。この際、以下に記載がある2つのオプションのいずれかが使用できます。

  • Configure an external volume and catalog integration(外部カタログと外部ボリュームの構成)
  • Use catalog-vended credentials for Apache Iceberg™ tables(カタログ提供の認証情報を使用してApache Iceberg テーブルにアクセスする)

この内、2つ目のオプションは現在書き込み操作はサポートしていないようです。そのため、ここでは1つ目のオプションを試してみます。

https://docs.snowflake.com/en/user-guide/tables-iceberg-catalog-linked-database#configure-access

外部管理テーブルへの書き込み用に外部ボリュームを構成する

こちらの手順は以下に記載があります。これまで通りの Snowflake から外部カタログを使用する Iceberg テーブルを定義する方法と変わりません。

https://docs.snowflake.com/en/user-guide/tables-iceberg-externally-managed-writes#configuring-an-external-volume-for-writes-to-externally-managed-tables

今回は S3 を使用するので、この手順は以下に記載があります。

https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-external-volume-s3

ここでは以下のポリシーで外部ボリュームを定義すしました。

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": [
				"s3:PutObject",
				"s3:GetObject",
				"s3:GetObjectVersion",
				"s3:DeleteObject",
				"s3:DeleteObjectVersion"
			],
			"Resource": "arn:aws:s3:::<バケット名>/*"
		},
		{
			"Effect": "Allow",
			"Action": [
				"s3:ListBucket",
				"s3:GetBucketLocation"
			],
			"Resource": "arn:aws:s3:::<バケット名>",
			"Condition": {
				"StringLike": {
					"s3:prefix": [
						"*"
					]
				}
			}
		}
	]
}

ポリシーをIAMロールに関連付けておきます。

続けて Snowflake 側で以下のコマンドを実行し外部ボリュームを作成します。

CREATE OR REPLACE EXTERNAL VOLUME exvol
   STORAGE_LOCATIONS =
      (
         (
            NAME = 'my-s3-ap-northeast-1'
            STORAGE_PROVIDER = 'S3'
            STORAGE_BASE_URL = 's3://<バケット名>/'
            STORAGE_AWS_ROLE_ARN = 'arn:aws:iam::xxxxxxxxxxxx:role/<role名>'
            ENCRYPTION=(TYPE='AWS_SSE_S3')
         )
      );

ここでは明示的に設定しませんでしたが、ALLOW_WRITESオプションはデフォルト(TRUE)とします。

https://docs.snowflake.com/en/sql-reference/sql/create-external-volume

外部ボリューム作成後は、以下のコマンドを実行し Snowflake アカウントの IAM ユーザーと外部 ID を取得し、IAM ロールの信頼関係を更新します。

DESC EXTERNAL VOLUME exvol;

外部カタログ統合の構成

外部カタログへのアクセス設定を行います。

ポイントとして、書き込み操作には、カタログ側で Iceberg REST OpenAPI 仕様に準拠している必要があります。AWS Glue Data Catalog は Iceberg REST API 互換のエンドポイントを介して、Iceberg テーブルのメタデータにアクセスするように設定できます。

https://docs.aws.amazon.com/ja_jp/glue/latest/dg/iceberg-rest-apis.html

この際、カタログ統合はこちらに記載がある AWS Glue のカタログ統合ではなく、以下で定義できる Iceberg REST カタログ統合を使用します。

https://docs.snowflake.com/en/sql-reference/sql/create-catalog-integration-rest

アクセスには IAM を使用できるので、外部管理テーブルへの書き込みアクセス可能なポリシーを設定します。サンプルは以下に記載があります。

https://docs.snowflake.com/en/user-guide/tables-iceberg-configure-catalog-integration-rest-glue#read-and-write-example-policy

ここでは以下のポリシーを定義し使用しました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowGlueCatalogAccess",
            "Effect": "Allow",
            "Action": [
                "glue:GetCatalog",
                "glue:GetDatabase",
                "glue:GetDatabases",
                "glue:CreateDatabase",
                "glue:DeleteDatabase",
                "glue:CreateTable",
                "glue:UpdateTable",
                "glue:DeleteTable",
                "glue:GetTable",
                "glue:GetTables",
                "glue:GetPartition",
                "glue:GetPartitions",
                "glue:CreatePartition",
                "glue:UpdatePartition",
                "glue:DeletePartition"
            ],
            "Resource": [
                "arn:aws:glue:*:xxxxxxxxxxxx:catalog",
                "arn:aws:glue:*:xxxxxxxxxxxx:database/*",
                "arn:aws:glue:*:xxxxxxxxxxxx:table/*/*",
                "arn:aws:glue:*:xxxxxxxxxxxx:partition/*/*/*"
            ]
        },
        {
            "Sid": "AllowS3AccessForIcebergData",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::<バケット名>",
                "arn:aws:s3:::<バケット名>/*"
            ]
        }
    ]
}

ポリシーをロールに関連付けたら、IAMロールの Arn を指定し以下の内容でカタログ統合を定義しました。

CREATE CATALOG INTEGRATION glue_rest_catalog_int
  CATALOG_SOURCE = ICEBERG_REST
  TABLE_FORMAT = ICEBERG
  CATALOG_NAMESPACE = 'sql_server'
  REST_CONFIG = (
    CATALOG_URI = 'https://glue.ap-northeast-1.amazonaws.com/iceberg'
    CATALOG_API_TYPE = AWS_GLUE
    CATALOG_NAME = 'xxxxxxxxxxxx' --CATALOG_API_TYPE = AWS_GLUEの場合はAWSアカウントのIDを指定
  )
  REST_AUTHENTICATION = (
    TYPE = SIGV4
    SIGV4_IAM_ROLE = 'arn:aws:iam::xxxxxxxxxxxx:role/<ロール名>'
    SIGV4_SIGNING_REGION = 'ap-northeast-1'
  )
  ENABLED = TRUE;

ここでは明示的に定義していませんが、自動更新の頻度(REFRESH_INTERVAL_SECONDS:デフォルトは30秒)なども指定できます。

https://docs.snowflake.com/en/sql-reference/sql/create-catalog-integration-rest

統合オブジェクト作成後は、外部ボリューム構成時と同様に以下を実行し IAM ロールの信頼関係を更新します。

DESCRIBE CATALOG INTEGRATION glue_rest_catalog_int;

カタログリンクデータベースの作成

外部ボリュームと Iceberg REST 準拠の外部カタログ統合使用することで、カタログリンクデータベースを作成できます。

--Catalog-linked databaseの作成
CREATE DATABASE my_linked_db
  LINKED_CATALOG = (
    CATALOG = 'glue_rest_catalog_int'
  )
  EXTERNAL_VOLUME = 'exvol';

特に指定しませんでしたが、ALLOWED_NAMESPACESオプションで自動テーブル検出の範囲を制御できます。

https://docs.snowflake.com/en/sql-reference/sql/create-database-catalog-linked

作成したデータベースのスキーマを確認すると以下のようになっていました。

>USE DATABASE MY_LINKED_DB;
+----------------------------------+
| status                           |
|----------------------------------|
| Statement executed successfully. |
+----------------------------------+

>SHOW SCHEMAS;
+-------------------------------+--------------------+------------+------------+---------------+--------------+-----------------------------------------------------------+---------+----------------+-----------------+---------------------------------+-------------------------------+------------------------+-------------------+
| created_on                    | name               | is_default | is_current | database_name | owner        | comment                                                   | options | retention_time | owner_role_type | classification_profile_database | classification_profile_schema | classification_profile | object_visibility |
|-------------------------------+--------------------+------------+------------+---------------+--------------+-----------------------------------------------------------+---------+----------------+-----------------+---------------------------------+-------------------------------+------------------------+-------------------|
| 2025-07-30 00:34:16.969 -0700 | INFORMATION_SCHEMA | N          | N          | MY_LINKED_DB  |              | Views describing the contents of schemas in this database |         | 1              |                 | NULL                            | NULL                          | NULL                   | NULL              |
| 2025-07-30 00:32:58.641 -0700 | sql_server_dbo     | N          | N          | MY_LINKED_DB  | ACCOUNTADMIN |                                                           |         | 1              | ROLE            | NULL                            | NULL                          | NULL                   | NULL              |
+-------------------------------+--------------------+------------+------------+---------------+--------------+-----------------------------------------------------------+---------+----------------+-----------------+---------------------------------+-------------------------------+------------------------+-------------------+

テーブルを確認すると、Fivetran 側で作成されたテーブルを確認できました。

>USE SCHEMA "sql_server_dbo";
+----------------------------------+
| status                           |
|----------------------------------|
| Statement executed successfully. |
+----------------------------------+

>SHOW TABLES;
+-------------------------------+------------+---------------+----------------+---------------+---------+------------+------+-------+--------------+----------------+----------------------+-----------------+---------------------+------------------------------+---------------------------+-------------+-------------------------+-----------------+----------+-----------+------------+------------+--------------+
| created_on                    | name       | database_name | schema_name    | kind          | comment | cluster_by | rows | bytes | owner        | retention_time | automatic_clustering | change_tracking | search_optimization | search_optimization_progress | search_optimization_bytes | is_external | enable_schema_evolution | owner_role_type | is_event | is_hybrid | is_iceberg | is_dynamic | is_immutable |
|-------------------------------+------------+---------------+----------------+---------------+---------+------------+------+-------+--------------+----------------+----------------------+-----------------+---------------------+------------------------------+---------------------------+-------------+-------------------------+-----------------+----------+-----------+------------+------------+--------------|
| 2025-07-30 00:32:59.234 -0700 | customers  | MY_LINKED_DB  | sql_server_dbo | ICEBERG_TABLE |         |            |    3 |  1856 | ACCOUNTADMIN | 5              | OFF                  | ON              | OFF                 |                         NULL |                      NULL | N           | N                       | ROLE            | N        | N         | Y          | N          | N            |
| 2025-07-30 00:32:59.249 -0700 | orders     | MY_LINKED_DB  | sql_server_dbo | ICEBERG_TABLE |         |            |    4 |  1561 | ACCOUNTADMIN | 5              | OFF                  | ON              | OFF                 |                         NULL |                      NULL | N           | N                       | ROLE            | N        | N         | Y          | N          | N            |
| 2025-07-30 00:32:59.251 -0700 | sampledata | MY_LINKED_DB  | sql_server_dbo | ICEBERG_TABLE |         |            | 1000 | 14343 | ACCOUNTADMIN | 5              | OFF                  | ON              | OFF                 |                         NULL |                      NULL | N           | N                       | ROLE            | N        | N         | Y          | N          | N            |
+-------------------------------+------------+---------------+----------------+---------------+---------+------------+------+-------+--------------+----------------+----------------------+-----------------+---------------------+------------------------------+---------------------------+-------------+-------------------------+-----------------+----------+-----------+------------+------------+--------------+

クエリ

>SELECT * FROM "customers";
+------------+---------------------------+------------------+-----------+----------+-------------------+-------------------------------+
| customerid | email                     | registrationdate | firstname | lastname | _fivetran_deleted | _fivetran_synced              |
|------------+---------------------------+------------------+-----------+----------+-------------------+-------------------------------|
|          1 | taro.yamada@example.com   | 2025-07-30       | Taro      | Yamada   | False             | 2025-07-29 22:50:54.700 -0700 |
|          2 | hanako.suzuki@example.com | 2025-07-30       | Hanako    | Suzuki   | False             | 2025-07-29 22:50:54.720 -0700 |
|          3 | ken.tanaka@example.com    | 2025-07-30       | Ken       | Tanaka   | False             | 2025-07-29 22:50:54.720 -0700 |
+------------+---------------------------+------------------+-----------+----------+-------------------+-------------------------------+

>SELECT * FROM "orders";
+---------+----------------+------------+------------+-------------------+-------------------------------+
| orderid |    totalamount | customerid | orderdate  | _fivetran_deleted | _fivetran_synced              |
|---------+----------------+------------+------------+-------------------+-------------------------------|
|       1 | 150.7500000000 |          1 | 2025-07-30 | False             | 2025-07-29 22:50:54.700 -0700 |
|       2 |  25.0000000000 |          1 | 2025-07-30 | False             | 2025-07-29 22:50:54.711 -0700 |
|       3 | 300.5000000000 |          2 | 2025-07-30 | False             | 2025-07-29 22:50:54.712 -0700 |
|       4 |  10.2000000000 |          3 | 2025-07-30 | False             | 2025-07-29 22:50:54.712 -0700 |
+---------+----------------+------------+------------+-------------------+-------------------------------+

>SELECT * FROM "sampledata" LIMIT 5;
+-----+--------------+--------------+------------+-------------------+-------------------------------+
|  id | randomnumber | randomstring | randomdate | _fivetran_deleted | _fivetran_synced              |
|-----+--------------+--------------+------------+-------------------+-------------------------------|
| 128 |          257 | 79EBD421-B   | 2005-07-19 | False             | 2025-07-29 22:13:24.764 -0700 |
| 384 |          792 | B10B8F4F-C   | 2000-02-07 | False             | 2025-07-29 22:13:24.779 -0700 |
| 640 |           78 | FDE7901A-B   | 2004-05-11 | False             | 2025-07-29 22:13:24.785 -0700 |
| 896 |          571 | 4D31BEEF-5   | 2007-11-22 | False             | 2025-07-29 22:13:24.789 -0700 |
| 129 |          891 | 47FBD84F-E   | 2004-02-05 | False             | 2025-07-29 22:13:24.764 -0700 |
+-----+--------------+--------------+------------+-------------------+-------------------------------+

書き込み操作を行う

Iceberg REST 準拠の外部カタログ統合使用し、カタログリンクデータベースとして定義したので、書き込み操作が可能です。

ここでは元テーブルを Fivetran で作成したため、本来はこのケースでは Snowflake から書き込み操作をすることはあまりないと思いますが、検証のため試しています。

--customersテーブルにレコードを追加
>INSERT INTO "customers" (
    "customerid",
    "email",
    "registrationdate",
    "firstname",
    "lastname",
    "_fivetran_deleted", 
    "_fivetran_synced"   
)
VALUES (
    4, 
    'jiro.sato@example.com',
    CURRENT_DATE(),
    'Jiro',
    'Sato',
    NULL, -- _fivetran_deleted はNULL
    NULL  -- _fivetran_synced はNULL
);
+-------------------------+
| number of rows inserted |
|-------------------------|
|                       1 |
+-------------------------+

--レコードを確認
>SELECT * FROM "customers";
+------------+---------------------------+------------------+-----------+----------+-------------------+-------------------------------+
| customerid | email                     | registrationdate | firstname | lastname | _fivetran_deleted | _fivetran_synced              |
|------------+---------------------------+------------------+-----------+----------+-------------------+-------------------------------|
|          4 | jiro.sato@example.com     | 2025-07-30       | Jiro      | Sato     | NULL              | NULL                          |
|          1 | taro.yamada@example.com   | 2025-07-30       | Taro      | Yamada   | False             | 2025-07-29 22:50:54.700 -0700 |
|          2 | hanako.suzuki@example.com | 2025-07-30       | Hanako    | Suzuki   | False             | 2025-07-29 22:50:54.720 -0700 |
|          3 | ken.tanaka@example.com    | 2025-07-30       | Ken       | Tanaka   | False             | 2025-07-29 22:50:54.720 -0700 |
+------------+---------------------------+------------------+-----------+----------+-------------------+-------------------------------+

問題なく書き込めました。

Athena で確認すると図のようにレコードが追加されていました。

image 1

反対に Athena 側からレコードを追加してみます。

image 2

Snowflake 側で確認すると、自動同期が完了したタイミングでレコードが反映されていました。

>select * from my_linked_db."sql_server_dbo"."customers";
+------------+---------------------------+------------------+-----------+----------+-------------------+-------------------------------+
| customerid | email                     | registrationdate | firstname | lastname | _fivetran_deleted | _fivetran_synced              |
|------------+---------------------------+------------------+-----------+----------+-------------------+-------------------------------|
|          5 | tom.brawn@example.com     | 2025-07-31       | Tom       | Brawn    | NULL              | NULL                          |
|          4 | jiro.sato@example.com     | 2025-07-30       | Jiro      | Sato     | NULL              | NULL                          |
|          1 | taro.yamada@example.com   | 2025-07-30       | Taro      | Yamada   | False             | 2025-07-29 22:50:54.700 -0700 |
|          2 | hanako.suzuki@example.com | 2025-07-30       | Hanako    | Suzuki   | False             | 2025-07-29 22:50:54.720 -0700 |
|          3 | ken.tanaka@example.com    | 2025-07-30       | Ken       | Tanaka   | False             | 2025-07-29 22:50:54.720 -0700 |
+------------+---------------------------+------------------+-----------+----------+-------------------+-------------------------------+

Iceberg テーブルを追加する

カタログリンクデータベースを使用する場合は、CREATE ICEBERG TABLE により、Snowflake とリモート側のカタログにテーブルを作成できます。

https://docs.snowflake.com/en/user-guide/tables-iceberg-externally-managed-writes

以下のようにテーブルを追加してみます。

USE DATABASE MY_LINKED_DB;
USE SCHEMA "sql_server_dbo";

>CREATE ICEBERG TABLE "my_iceberg_table"(
  "first_name" STRING,
  "last_name" STRING,
  "amount" INT,
  "create_date" DATE
)
  PARTITION BY ("first_name");
 +----------------------------------------------+
| status                                       |
|----------------------------------------------|
| Table my_iceberg_table successfully created. |
+----------------------------------------------+

--insertする
>INSERT INTO "my_iceberg_table" (
    "first_name",
    "last_name",
    "amount",
    "create_date"
)
VALUES
    ('Alice', 'Smith', 100, '2025-07-29'),
    ('Bob', 'Johnson', 150, '2025-07-29'),
    ('Alice', 'Williams', 200, '2025-07-30');
+-------------------------+
| number of rows inserted |
|-------------------------|
|                       3 |
+-------------------------+

>SELECT * FROM "my_iceberg_table";
+------------+-----------+--------+-------------+
| first_name | last_name | amount | create_date |
|------------+-----------+--------+-------------|
| Bob        | Johnson   |    150 | 2025-07-29  |
| Alice      | Smith     |    100 | 2025-07-29  |
| Alice      | Williams  |    200 | 2025-07-30  |
+------------+-----------+--------+-------------+

>SHOW TABLES;
+-------------------------------+------------------+---------------+----------------+---------------+---------+------------+------+-------+--------------+----------------+----------------------+-----------------+---------------------+------------------------------+---------------------------+-------------+-------------------------+-----------------+----------+-----------+------------+------------+--------------+
| created_on                    | name             | database_name | schema_name    | kind          | comment | cluster_by | rows | bytes | owner        | retention_time | automatic_clustering | change_tracking | search_optimization | search_optimization_progress | search_optimization_bytes | is_external | enable_schema_evolution | owner_role_type | is_event | is_hybrid | is_iceberg | is_dynamic | is_immutable |
|-------------------------------+------------------+---------------+----------------+---------------+---------+------------+------+-------+--------------+----------------+----------------------+-----------------+---------------------+------------------------------+---------------------------+-------------+-------------------------+-----------------+----------+-----------+------------+------------+--------------|
| 2025-07-30 00:32:59.234 -0700 | customers        | MY_LINKED_DB  | sql_server_dbo | ICEBERG_TABLE |         |            |    4 |  3392 | ACCOUNTADMIN | 5              | OFF                  | ON              | OFF                 |                         NULL |                      NULL | N           | N                       | ROLE            | N        | N         | Y          | N          | N            |
| 2025-07-30 00:50:19.525 -0700 | my_iceberg_table | MY_LINKED_DB  | sql_server_dbo | ICEBERG_TABLE |         |            |    3 |  2048 | ACCOUNTADMIN | 1              | OFF                  | ON              | OFF                 |                         NULL |                      NULL | N           | N                       | ROLE            | N        | N         | Y          | N          | N            |
| 2025-07-30 00:32:59.249 -0700 | orders           | MY_LINKED_DB  | sql_server_dbo | ICEBERG_TABLE |         |            |    4 |  1561 | ACCOUNTADMIN | 5              | OFF                  | ON              | OFF                 |                         NULL |                      NULL | N           | N                       | ROLE            | N        | N         | Y          | N          | N            |
| 2025-07-30 00:32:59.251 -0700 | sampledata       | MY_LINKED_DB  | sql_server_dbo | ICEBERG_TABLE |         |            | 1000 | 14343 | ACCOUNTADMIN | 5              | OFF                  | ON              | OFF                 |                         NULL |                      NULL | N           | N                       | ROLE            | N        | N         | Y          | N          | N            |
+-------------------------------+------------------+---------------+----------------+---------------+---------+------------+------+-------+--------------+----------------+----------------------+-----------------+---------------------+------------------------------+---------------------------+-------------+-------------------------+-----------------+----------+-----------+------------+------------+--------------+

問題なく作成できました。

こちらも Athena で確認できました。

image 3

Athena 側からレコードを追加してみます。

image 4

カタログリンクデータベースは自動同期されるので新規テーブルも自動更新されると思ったのですが、この場合、自動的に更新が反映されませんでした。

以下の操作後、自動で更新内容が反映されるようになりました。

ALTER ICEBERG TABLE "sql_server_dbo"."my_iceberg_table" SET AUTO_REFRESH = TRUE;

更新ステータスは以下で確認できます。

show iceberg tables;

さいごに

新機能であるカタログリンク データベースを使用し、外部管理の Iceberg テーブルへの書き込み操作を試してみました。
カタログリンクデータベースを使用すると、外部カタログと Snowflake が自動的に同期され、対応するリモートテーブルがカタログリンクデータベースに自動登録されるため、個々の Iceberg テーブルを定義する必要がなくなります。
現時点では制約も多いですが、書き込み操作もサポートされているので、より Iceberg エコシステムでデータを利用しやすくなるアップデートと思います。
こちらの内容が何かの参考になれば幸いです。

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.