寝ても覚めてもこんぴうた

プログラム書いたり、ネットワーク設計したり、サーバ構築したり、車いじったり、ゲームしたり。そんなひとにわたしはなりたい。 投げ銭は kyash_id : chidakiyo マデ

Spanner の DDL (スキーマ)管理を行う hammer を試してみた

f:id:chidakiyo:20200902100259j:plain

Datastore を利用していたときにはスキーマがあってなかったようなものなので、基本的にはエンティティの定義 ≒ スキーマみたいなところがあったが、Spannerは正統派RDB的な振る舞いをするので、 DDL によってスキーマを定義します。

スキーマの設計自体を DDL で行った場合、運用が始まったテーブルに対してはスキーマ自体ではなく、差分のクエリを発行する必要があります。(ALTER TABLE)

RDB を使ってきた人としては「まぁそうだよね」という感じの話ではあるが、毎回差分を把握して ALTER 文を作成するのも面倒なので、そのあたり「いいかんじ」にやってくれるという hammer を試してみます。

hammer をインストールする。

インストールにはバイナリでインストールする方法と、 go get を利用する方法がありますが、私の環境は go がすでにインストールされてるため、 go get コマンドを利用してインストールします。

go get -u github.com/daichirata/hammer

インストールが終わるまでちょっと待ちます。

注意 : Spannerライブラリ1.9 で若干構成が変わっているため go get でインストールできない場合があります。その場合はバイナリからのインストールをおすすめします。(2020/09/02現在)

インストールを確認

以下のコマンドで正しくインストールされたか確認してみましょう

hammer

色々それっぽい情報(?)が表示されれば OK です。(-v オプション実装されてない??)

2つのファイルから差分を出してみる

ドキュメントの例の通り、以下のような2つのファイルを用意してみます。

users.sql

CREATE TABLE users (
  user_id STRING(36) NOT NULL,
) PRIMARY KEY(user_id);

users2.sql

CREATE TABLE users (
  user_id STRING(36) NOT NULL,
  age INT64,
  name STRING(MAX) NOT NULL,
) PRIMARY KEY(user_id);
CREATE INDEX idx_users_name ON users (name);

これらを用意した上で以下のコマンドを実行してみます

hammer diff users.sql users2.sql

結果は以下のように表示されました。

ALTER TABLE users ADD COLUMN age INT64
ALTER TABLE users ADD COLUMN name STRING(MAX)
UPDATE users SET name = '' WHERE name IS NULL
ALTER TABLE users ALTER COLUMN name STRING(MAX) NOT NULL
CREATE INDEX idx_users_name ON users(name)

良さそうな感じですが、befor/after の2つのファイルを用意するというパターンは Git で DDL を管理している場合にはあまり発生しないパターンだと思うので、 Spanner の DB と直接比較するパターンを試してみます。

DB とファイルの差分を出してみる。

先程の users.sql を Spanner 側に適用した状態で、 users2.sql と比較してみます。

hammer diff spanner://projects/{PROJECT_ID}/instances/{INSTANCE_ID/databases/{DB_NAME} users2.sql

コマンドを実行すると以下のような結果が表示されました

ALTER TABLE users ADD COLUMN age INT64
ALTER TABLE users ADD COLUMN name STRING(MAX)
UPDATE users SET name = '' WHERE name IS NULL
ALTER TABLE users ALTER COLUMN name STRING(MAX) NOT NULL
CREATE INDEX idx_users_name ON users(name)

先ほどと同じ感じになりますね。
DBに適用したスキーマをベースに、新しく追加した DDL との差分を得るという運用の場合にはこの感じで利用できそうです。

おまけ : スキーマファイルを Spanner DB に適用する

ファイルを DB に適用する場合には apply コマンドを利用します。

hammer apply spanner://projects/{PROJECT_ID}/instances/{INSTANCE_ID/databases/{DB_NAME} users2.sql

ただ、裏側で何をやっているかあまり把握できていないので、プロダクション環境では利用しない感じでしょうか。

ちょっと不安な点

diff の定義的に、(コマンドでファイル連結するてもあるが) DDL ファイルは1ファイルで管理するイメージになるでしょうか。
テーブルなどが増えてきた際にファイル分割したくなったりするパターンもあるかな?
と思うところもあったので、使ってみて使用感とかまたアウトプットできればと思います。

ではでは。

参考

Spanner で 羃等スキーマ管理をするツール hammer の話 - Qiita