
SnowflakeのDBマイグレーションツールであるschemachangeを使ってみた
データ事業本部のueharaです。
今回は、SnowflakeのDBマイグレーションツールであるschemachangeを使ってみたいと思います。
schemachangeとは
schemachange は、 Snowflakeのコミュニティ開発ツールとして提供されているPythonベースのDBマイグレーションツールです。
同じくDBのマイグレーションツールとして有名な Flyway の仕組みをベースに考えられており、既にFlywayを利用したことがある方であれば取っ付きやすいツールかと思います。
バージョン管理をする変更スクリプト(SQLファイル)の命名規則は、Flywayで使用される命名規則に従う形になっています。

(参考)
- Prefix: バージョン変更を表す文字である「V」
- Version: ドットまたはアンダースコアで任意の数の数字部分を区切った一意のバージョン番号
- Separator:
__(アンダースコア2つ) - Description: アンダースコアまたはスペースで区切られた単語による任意の説明(2つのアンダースコアを含めることはできない)
- Suffix:
.sqlまたは.sql.jinja(大文字と小文字は区別されない)
またschemachangeでは、バージョン管理を行うスクリプト( V )だけではなく、繰り返し可能なスクリプト( R )と常に実行されるスクリプト( A )にも対応しています。
| Prefix | 名称 | 挙動 | スクリプトの例 |
|---|---|---|---|
V |
Versioned | 1回のみ実行 | V1.0.0__create_users_table.sql |
R |
Repeatable | チェックサム変更時に再実行 | R__create_user_view.sql |
A |
Always | 毎回実行 | A__grant_permissions.sql |
一方で、実行可能なコマンドとしてFlywayと比較しschemachangeはより簡易的なものとなっています。
| 機能 | Flyway | Schemachange |
|---|---|---|
| マイグレーション実行 | migrate |
deploy |
| 状態確認 | info |
なし |
| 検証 | validate |
verify(接続確認のみ) |
| テンプレート確認 | なし | render |
| 修復 | repair |
なし |
| 全削除 | clean |
なし |
| ベースライン | baseline |
なし |
schemachangeは、(少なくとも記事執筆時点では)よりシンプルさを重視した設計であるように見えます。
やってみた
事前準備
Snowflake上で、事前に UEHARA_TEST_DB と METADATA という名前のDBを作成しておきます。
USE ROLE SYSADMIN;
CREATE DATABASE UEHARA_TEST_DB;
CREATE DATABASE METADATA;

後段の処理ではこれらのDBを使うことにします。
schemachangeのインストール
まず、schemachangeのインストールを行います。
冒頭で述べた通りPythonベースのツールとなっているので、以下コマンドでインストールできます。
pip install schemachange
初回のファイル作成
手始めに、以下のようなディレクトリ構成を作成します。
.
├── migrations
│ ├── V1.0.0__create_test_schema.sql
│ └── V1.1.0__create_items_table.sql
└── schemachange-config.yml
schemachange-config.yml はschemachangeの設定ファイルになります。
記載方法についてはドキュメントに記載の通りですが、今回は以下のようにしてみました。
config-version: 2
schemachange:
# The root folder for the database change scripts
root-folder: './migrations'
# Used to override the default name of the change history table (default: METADATA.SCHEMACHANGE.CHANGE_HISTORY)
change-history-table: 'METADATA.SCHEMACHANGE.CHANGE_HISTORY'
# Define values for variables to be replaced in change scripts
vars:
environment: 'dev'
# Create the change history schema and table if they do not exist (default: false)
create-change-history-table: true
# Log level: DEBUG, INFO, WARNING, ERROR, or CRITICAL (default: INFO)
log-level: 'INFO'
# Regex pattern for version number validation
version-number-validation-regex: '^[0-9]+\.[0-9]+\.[0-9]+$'
最初に作る変更スクリプトは以下のようにしてみました。
CREATE SCHEMA TEST_SCHEMA;
CREATE TABLE TEST_SCHEMA.ITEMS (
id INTEGER PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price INTEGER NOT NULL
);
接続設定と疎通確認
Snowflakeの接続情報として、環境変数に値を設定します。
export SNOWFLAKE_ACCOUNT="<YOUR_ACCOUNT>"
export SNOWFLAKE_USER="<YOUR_USER>"
export SNOWFLAKE_PRIVATE_KEY_PATH="<YOUR_KEY_PATH>"
export SNOWFLAKE_PRIVATE_KEY_PASSPHRASE="<YOUR_KEY_PASSPHRASE>"
export SNOWFLAKE_ROLE="<YOUR_ROLE>"
export SNOWFLAKE_WAREHOUSE="<YOUR_WAREHOUSE>"
export SNOWFLAKE_DATABASE="<YOUR_DB>"
設定ができたら、以下コマンドで疎通確認を行います。
schemachange verify
出力の最後に以下のように表示されれば接続ができています。

デプロイ(1回目)
接続の確認ができたので、デプロイしてみます。
schemachange deploy
出力の最後に以下のように表示されていればデプロイ成功です。

実際にSnowlake上にデータを見に行くと、変更履歴の管理用テーブルとSQLで指定したスキーマ及びテーブルが作成されていることが分かります。

変更履歴のテーブルを確認すると、以下のように実行ステータスの確認ができます。

ファイルの追加
次に、以下の通りファイルの追加をしてみます。
.
├── migrations
│ ├── R__items_view.sql ★新規作成
│ ├── V1.0.0__create_test_schema.sql
│ ├── V1.1.0__create_items_table.sql
│ └── V1.1.1__alter_items_add_column.sql ★新規作成
└── schemachange-config.yml
追加した2ファイルは以下の通りです。
CREATE OR REPLACE VIEW TEST_SCHEMA.ITEMS_VIEW AS
SELECT
id,
name,
price,
description
FROM TEST_SCHEMA.ITEMS;
ALTER TABLE TEST_SCHEMA.ITEMS ADD COLUMN description VARCHAR(1024);
デプロイ(2回目)
ファイルの追加が完了したので、再度デプロイを行います。
schemachange deploy
結果は次の通りで、バージョン指定したものについては履歴からMaxのバージョンを確認し、以降のスクリプトが実行されていることが分かります。
R で指定したビューは現状未作成のものなので、このタイミングで新規作成されています。

Snoflake上でもビューの作成とテーブルへのカラムの追加が確認できました。


このタイミングでもう1度デプロイを実行してみます。
schemachange deploy
結果は次の通りで、反映すべきスクリプトが無いので何も適用していないことが分かります。

異常系の動作確認
正常系は何となく挙動が見れたので、今度はあえて誤った操作をしてみます。
バージョンを誤ったファイルの追加
既に適用済みのバージョンより過去のバージョンのファイルを追加してみます。
.
├── migrations
│ ├── R__items_view.sql
│ ├── V1.0.0__create_test_schema.sql
│ ├── V1.0.1__create_sample_schema.sql ★新規作成
│ ├── V1.1.0__create_items_table.sql
│ └── V1.1.1__alter_items_add_column.sql
└── schemachange-config.yml
この状態でデプロイを実行すると、エラーメッセージは特に出ませんが、ファイルがSkipされるため、シンプルに適用がされません。
schemachange deploy

環境反映済みのバージョン管理スクリプトの修正
今度は、既に環境反映済みのバージョン管理スクリプトを修正してみます。
ALTER TABLE TEST_SCHEMA.ITEMS ADD COLUMN description VARCHAR(1024);
+ALTER TABLE TEST_SCHEMA.ITEMS ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP();
先程の挙動から明らかにはなりますが、この状態でデプロイしてもバージョン的に処理はスキップされるため、反映はされません。
schemachange deploy

ここが少し事故が起こりそうだなと思う部分ですが、過去のバージョンの作成や、適用済みのファイルに変更を加えたとしてもデプロイコマンドでは特にエラーにはなりません。
Flywayであればこのようなケースではデプロイ(migrate)時にエラーとなりますが、schemachangeはそのようになっていないようなので注意が必要です。
補足:Jinjaテンプレートの活用
schemachangeではJinjaテンプレートをサポートしているため、動的なSQLスクリプトが作成可能です。
例えば先の schemachange-config.yml では、変数として以下を設定していました。
vars:
environment: 'dev'
これを利用し、例えば以下のようなスクリプトファイルの記述が可能です。
CREATE TABLE TEST_SCHEMA.{{environment}}_USERS (
id INTEGER PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
render コマンドを利用することで、どのようなSQLファイルが実行されるか確認することもできます。
schemachange render migrations/V1.2.0__create_users_table.sql

ちなみに変数はデプロイ時に --vars オプションで変更可能なので、例えば環境毎に変数を上書きすることもできます。
schemachange render --vars '{"environment": "prod"}' migrations/V1.2.0__create_users_table.sql

最後に
今回は、SnowflakeのDBマイグレーションツールであるschemachangeを使ってみました。
参考になりましたら幸いです。







