sqldefはRDBMSのスキーマをconfigに沿って更新するCLIツールです。
先行実装
ridgepoleのGoクローンと言えます。
Webフレームワークで標準的なマイグレーションと異なり、スキーマバージョン間の差分ではなく要求スキーマを一括で定義するものです。
マイグレーションは仕上がりのスキーマをDBに実装しないと確認できませんが、ridgepoleやsqldefはconfigが仕様であり、この点が決定的に異なります。
sqldefとridgepoleの違い
sqldefとridgepoleは目的が同じであるためユーザーは競合するのですが、configの言語が異なるため決定的に優劣が付くことはないでしょう。プロジェクトが重視する点に応じて選択します。
- sqldefのスキーマ定義はSQL。SQLは完全互換でないこともあり、DBMSごとにmysqldef/psqldef/sqlite3def/mssqldefがあり挙動も異なる
- ridgepoleのスキーマ定義はRailsマイグレーションDSL。原則としてDBMS間で記述が共通
両者の違いは外から機能比較しても理解できません。
いずれのツールも主要機能として--export
オプションを備えているため、運用中のDBスキーマをconfigにダンプして見比べることが有効です。
最後は目視検証
マイグレーションやsqldef, ridgepoleはDBスキーマの品質維持を強力に支援します。
ただし、いずれのツールを採用したとしても、スキーマを正確に反映できていることや目的に沿った挙動になっていることには別途検証が必要です。
DBを含めた挙動確認にはユニットテストは無力で、インテグレーションテストが必要になります。
そしてインテグレーションテストを積み上げたとしても、矛盾がないことの保証は得られないため、最終的にはスキーマを手作業で目視検証することが重要であるように思います。
ridgepoleやsqldefのスキーマファイルはDB内の全テーブルを見渡せるため、論理的な検証をしやすい点がポイントと言えます。
行きがかり上、定義と実装が乖離する展開もあるのですが、その場合にも素朴に見比べやすいメリットがあります。
psqldefの運用
既述のとおりsqldefはDBMSごとのCLIを提供しており、PostgreSQL向けにはpsqldef
をPATHの有効ディレクトリに置いて使います。
# エクスポート
$ psqldef -U<DB user> --export [--skip-view] <DB name> [> <schema filename>]
# 適用
$ cat <schema filename> | psqldef -U<DB user> [--dry-run] [--skip-view] <DB name>
ユーザー指定のみ記載しましたが、ホストやパスワードのオプションは標準のpsql
コマンドに準じて指定します。
なお、想定どおりに動作しない場合、カラムがデータごと消える挙動などが起きうることをあらかじめ理解しておきましょう。
カラム名変更のつもりで削除&追加の挙動になるといった致命的な凡ミスがありえるため、マイグレーションとはメンタルモデルを切り替えなくてはなりません。
適用する前には、実DBの最新バックアップを取得しておくことが最重要です。
また、予行演習として--dry-run
の出力を確認しておくことも有効です。
psqlとの併用
psqldefはテーブルに加えてViewやMaterializedViewなども追跡するのですが、Viewは複雑なSELECT文をサポートすることから、エラーになることがあります。
--skip-view
オプションをつけると、これらを管理対象から除外します。この挙動の違いは--export
すると確認できます。
Viewを含めCREATE OR REPLACE
をサポートしているDBオブジェクトについては、もとより標準のpsql
コマンドで適切に更新できるため、psql
とpsqldef
を併用することで相当複雑なDBも管理できます。
Chuma Takahiro