0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Snowflake の CHANGES 句(STREAM)と Databricks の CHANGES 句の動作差異に関する調査結果

0
Last updated at Posted at 2026-04-09

概要

Snowflake の CHANGES 句(STREAM)と Databricks の CHANGES 句の動作差異について調査した内容を共有します。確認した差異は下記のとおりです。これらのサービス間で移行を行う際には、動作差異を踏まえたうえで作業を進める必要があります。

  • Snowflake と Databricks では、UPDATE 時の記録方法が異なること
  • Snowflake では複数の DML 操作が集約された単一レコードとして記録される一方で、Databricks では DML の処理内容を複数レコードとして取得できること
  • UPDATE と DELETE が同時に行われた場合、Snowflake では UPDATE 前の値に対して DELETE された形で記録される一方で、Databricks ではそれぞれの DML 操作を取得できること
  • INSERT と DELETE が同時に行われた場合、Snowflake ではそのレコードを取得できない一方で、Databricks ではそれぞれの DML 操作を取得できること

仕様差異

変更内容のメタデータ列の基本的な仕様

Snowflake と Databricks で CHANGES 句を利用した際に追加されるカラムは下記のとおりです。

image.png

出所: Introduction to streams | Snowflake Documentation

image.png

出所: Azure Databricks で Delta Lake の変更データ フィードを使用する - Azure Databricks | Microsoft Learn

UPDATE の仕様差異

UPDATE 時の取得方法が異なる点には注意が必要です。Snowflake では METADATA$ACTIONINSERT または DELETE であり、かつ METADATA$ISUPDATETRUE の条件で取得できます。一方、Databricks では _change_type 列が update_preimage および update_postimage の条件で取得できます。名称が異なる点にも注意が必要です。

動作再現

INSERT と UPDATE の動作確認

ID が 1 のレコードに対して、INSERT(valA) -> UPDATE(valB) -> UPDATE(valC)の処理を実施した結果が下記です。Snowflake では valC のみのレコードが表示されていることから、最終処理後のデータが取得できることを確認できます。一方、Databricks ではそれぞれの DML 操作に対応するレコードを取得できています。

Snowflake の結果

ID VAL TS ACTION IS_UPDATE ROW_ID
1 C 2026-04-08 19:27:47.408 INSERT FALSE cf574746f7d568aeb11338364d82b600fab2a701

image.png

Databricks の結果

id val ts _change_type _commit_version _commit_timestamp
1 A 2026-04-09T02:33:22.194+00:00 insert 1 2026-04-09T02:33:23.000+00:00
1 B 2026-04-09T02:33:23.357+00:00 update_postimage 2 2026-04-09T02:33:27.000+00:00
1 A 2026-04-09T02:33:22.194+00:00 update_preimage 2 2026-04-09T02:33:27.000+00:00
1 C 2026-04-09T02:33:27.244+00:00 update_postimage 3 2026-04-09T02:33:30.000+00:00
1 B 2026-04-09T02:33:23.357+00:00 update_preimage 3 2026-04-09T02:33:30.000+00:00

image.png

UPDATE と DELETE の動作確認

ID が 1 のレコードに対して、UPDATE(valD) -> DELETE の処理を実施した結果が下記です。Snowflake では valC のレコードのみが表示されていることから、UPDATE 前のレコードに対して DELETE されたデータが取得できることを確認できます。一方、Databricks ではそれぞれの DML 操作に対応するレコードを取得できています。UPDATE 後の値である D のレコードを取得できることを想定していたためSnowflake のこの動作は想定と異なる結果でしたが、前回からの差分と捉えればCのデータを削除したという解釈ができます。

Snowflake の結果

ID VAL ACTION IS_UPDATE ROW_ID
1 C DELETE FALSE cf574746f7d568aeb11338364d82b600fab2a701

image.png

Databricks の結果

id val ts _change_type _commit_version _commit_timestamp
1 D 2026-04-09T02:33:27.244+00:00 update_postimage 4 2026-04-09T02:33:39.000+00:00
1 C 2026-04-09T02:33:27.244+00:00 update_preimage 4 2026-04-09T02:33:39.000+00:00
1 D 2026-04-09T02:33:27.244+00:00 delete 5 2026-04-09T02:33:41.000+00:00

image.png

INSERT と DELETE の動作確認

ID が 2 のレコードに対して、INSERT(valZ) -> DELETE の処理を実施した結果が下記です。Snowflake ではデータを取得できない一方で、Databricks ではそれぞれの DML 操作に対応するレコードを取得できています。

Snowflake の結果

データなし。

image.png

Databricks の結果

id val ts _change_type _commit_version _commit_timestamp
2 Z 2026-04-09T02:33:47.363+00:00 insert 6 2026-04-09T02:33:48.000+00:00
2 Z 2026-04-09T02:33:47.363+00:00 delete 7 2026-04-09T02:33:50.000+00:00

image.png

検証コード

Snowflake

事前準備

CREATE DATABASE IF NOT EXISTS changes_test;
CREATE SCHEMA IF NOT EXISTS changes_test.schema_01;
USE DATABASE changes_test;
USE SCHEMA changes_test.schema_01;
-- Snowflake SQL
DROP TABLE IF EXISTS change_verify_sf;
CREATE TABLE change_verify_sf (
  id NUMBER,
  val STRING,
  ts timestamp
);

ALTER TABLE change_verify_sf SET CHANGE_TRACKING = TRUE;

-- ここで標準 stream を作成
CREATE OR REPLACE STREAM change_verify_sf_s
  ON TABLE change_verify_sf;

image.png

INSERT と UPDATE の動作確認

-- ここを区間開始点にする
SET ts_start = (SELECT CURRENT_TIMESTAMP());
INSERT INTO change_verify_sf VALUES (1, 'A', current_timestamp());

UPDATE change_verify_sf
SET val = 'B',ts = current_timestamp()
WHERE id = 1;

UPDATE change_verify_sf
SET val = 'C',ts = current_timestamp()
WHERE id = 1;

image.png

SELECT
  id,
  val,
  ts,
  METADATA$ACTION   AS action,
  METADATA$ISUPDATE AS is_update,
  METADATA$ROW_ID   AS row_id
FROM change_verify_sf
  CHANGES(INFORMATION => DEFAULT)
  AT(TIMESTAMP => $ts_start)
ORDER BY id, action;
ID VAL TS ACTION IS_UPDATE ROW_ID
1 C 2026-04-08 19:27:47.408 INSERT FALSE cf574746f7d568aeb11338364d82b600fab2a701

image.png

SELECT * FROM change_verify_sf_s;
ID VAL TS METADATA$ACTION METADATA$ISUPDATE METADATA$ROW_ID
1 C 2026-04-08 19:27:47.408 INSERT FALSE cf574746f7d568aeb11338364d82b600fab2a701

image.png

-- STREAM を消費
CREATE OR REPLACE TEMP TABLE temp_test_01
AS
SELECT * FROM change_verify_sf_s;

image.png

UPDATE と DELETE の動作確認

-- DELETE 前の状態を取得
SET ts_delete_pre = (SELECT CURRENT_TIMESTAMP());
UPDATE change_verify_sf
SET val = 'D',ts = current_timestamp()
WHERE id = 1;

UPDATE 時点での STREAM の結果を確認すると下記の結果となります。

SELECT * FROM change_verify_sf_s;
ID VAL TS METADATA$ACTION METADATA$ISUPDATE METADATA$ROW_ID
1 D 2026-04-08 19:27:54.575 INSERT TRUE cf574746f7d568aeb11338364d82b600fab2a701
1 C 2026-04-08 19:27:47.408 DELETE TRUE cf574746f7d568aeb11338364d82b600fab2a701

image.png

-- DELETE 直後の状態を取得
SET ts_delete_post = (SELECT CURRENT_TIMESTAMP());
DELETE FROM change_verify_sf
WHERE id = 1;

image.png

SELECT
  id,
  val,
  METADATA$ACTION   AS action,
  METADATA$ISUPDATE AS is_update,
  METADATA$ROW_ID   AS row_id
FROM change_verify_sf
  CHANGES(INFORMATION => DEFAULT)
  AT(TIMESTAMP => $ts_delete_pre)
  
ORDER BY id, action;
ID VAL ACTION IS_UPDATE ROW_ID
1 C DELETE FALSE cf574746f7d568aeb11338364d82b600fab2a701

image.png

SELECT * FROM change_verify_sf_s;
ID VAL TS METADATA$ACTION METADATA$ISUPDATE METADATA$ROW_ID
1 C 2026-04-08 19:27:47.408 DELETE FALSE cf574746f7d568aeb11338364d82b600fab2a701

image.png

DELETE 直後の CHANGES 句の結果は下記です。途中で STREAM で確認した結果と一致します。

SELECT
  id,
  val,
  METADATA$ACTION   AS action,
  METADATA$ISUPDATE AS is_update,
  METADATA$ROW_ID   AS row_id
FROM change_verify_sf
  CHANGES(INFORMATION => DEFAULT)
  AT(TIMESTAMP => $ts_delete_post)
  
ORDER BY id, action;
ID VAL ACTION IS_UPDATE ROW_ID
1 D DELETE FALSE cf574746f7d568aeb11338364d82b600fab2a701

image.png

-- STREAM を消費
CREATE OR REPLACE TEMP TABLE temp_test_02
AS
SELECT * FROM change_verify_sf_s;

image.png

INSERT と DELETE の動作確認

-- INSERT と DELETE の時点を取得
SET ts_insert_and_delete = (SELECT CURRENT_TIMESTAMP());
INSERT INTO change_verify_sf VALUES (2, 'Z', current_timestamp());

DELETE FROM change_verify_sf
WHERE id = 2;

image.png

SELECT
  id,
  val,
  METADATA$ACTION   AS action,
  METADATA$ISUPDATE AS is_update,
  METADATA$ROW_ID   AS row_id
FROM change_verify_sf
  CHANGES(INFORMATION => DEFAULT)
  AT(TIMESTAMP => $ts_insert_and_delete)
  
ORDER BY id, action;

image.png

SELECT * FROM change_verify_sf_s;

image.png

Databricks

事前準備

%sql
CREATE CATALOG IF NOT EXISTS changes_test;
CREATE SCHEMA IF NOT EXISTS changes_test.schema_01;
%sql
USE CATALOG changes_test;
USE changes_test.schema_01;
%sql
-- Databricks SQL
DROP TABLE IF EXISTS change_verify_dbx;
CREATE TABLE change_verify_dbx
 (
  id INT,
  val STRING,
  ts TIMESTAMP
)
TBLPROPERTIES (delta.enableChangeDataFeed = true);

image.png

INSERT と UPDATE の動作確認

%sql
-- version 1
INSERT INTO change_verify_dbx VALUES (1, 'A', current_timestamp());

-- version 2
UPDATE change_verify_dbx
SET val = 'B',ts = current_timestamp()
WHERE id = 1;

-- version 3
UPDATE change_verify_dbx
SET val = 'C',ts = current_timestamp()
WHERE id = 1;

image.png

%sql
SELECT
  id,
  val,
  ts,
  _change_type,
  _commit_version,
  _commit_timestamp
FROM table_changes('change_verify_dbx', 1)
ORDER BY _commit_version, id, _change_type;
id val ts _change_type _commit_version _commit_timestamp
1 A 2026-04-09T02:33:22.194+00:00 insert 1 2026-04-09T02:33:23.000+00:00
1 B 2026-04-09T02:33:23.357+00:00 update_postimage 2 2026-04-09T02:33:27.000+00:00
1 A 2026-04-09T02:33:22.194+00:00 update_preimage 2 2026-04-09T02:33:27.000+00:00
1 C 2026-04-09T02:33:27.244+00:00 update_postimage 3 2026-04-09T02:33:30.000+00:00
1 B 2026-04-09T02:33:23.357+00:00 update_preimage 3 2026-04-09T02:33:30.000+00:00

image.png

UPDATE と DELETE の動作確認

%sql
-- version 4
UPDATE change_verify_dbx
SET val = 'D'
WHERE id = 1;

-- version 5
DELETE FROM change_verify_dbx
WHERE id = 1;

image.png

%sql
SELECT
  id,
  val,
  ts,
  _change_type,
  _commit_version,
  _commit_timestamp
FROM table_changes('change_verify_dbx', 4)
ORDER BY _commit_version, id, _change_type;
id val ts _change_type _commit_version _commit_timestamp
1 D 2026-04-09T02:33:27.244+00:00 update_postimage 4 2026-04-09T02:33:39.000+00:00
1 C 2026-04-09T02:33:27.244+00:00 update_preimage 4 2026-04-09T02:33:39.000+00:00
1 D 2026-04-09T02:33:27.244+00:00 delete 5 2026-04-09T02:33:41.000+00:00

image.png

INSERT と DELETE の動作確認

%sql
-- version 6
INSERT INTO change_verify_dbx VALUES (2, 'Z', current_timestamp());

-- version 7
DELETE FROM change_verify_dbx
WHERE id = 2;

image.png

%sql
SELECT
  id,
  val,
  ts,
  _change_type,
  _commit_version,
  _commit_timestamp
FROM table_changes('change_verify_dbx', 6)
ORDER BY _commit_version, id, _change_type;
id val ts _change_type _commit_version _commit_timestamp
2 Z 2026-04-09T02:33:47.363+00:00 insert 6 2026-04-09T02:33:48.000+00:00
2 Z 2026-04-09T02:33:47.363+00:00 delete 7 2026-04-09T02:33:50.000+00:00

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?