概要
Djangoのようなフレームワークを使う際にはMigration Toolが内蔵されていますので特にどのツールを使おうか悩むことはないかと思いますが、FastAPIやFlaskなどの軽量フレームワークを使う際、Migration Toolを選定する必要があるかと思います。
そんな方のために現時点において主要な三つのPythonのMigration Toolをまとめてみました。
(2021/2/20現在)
Github | Github Stars | Github最終更新日 | 対応DB | DSL/RawSQL | ドキュメント | |
---|---|---|---|---|---|---|
alembic | https://github.com/sqlalchemy/alembic | 834 | 11 hours ago | MySQL, SQLServer,Postgresql, SQLite | Python/Raw SQL | https://alembic.sqlalchemy.org/en/latest/ |
simple-db-migrate | https://github.com/guilhermechapiewski/simple-db-migrate | 186 | 5 months ago | MySQL | Raw SQL | Githubのみ |
yoyo-migration | https://github.com/marcosschroh/yoyo-database-migrations | 9 | 13 months ago | PostgreSQL, MySQL, SQLite | Python / Raw SQL | https://ollycope.com/software/yoyo/latest/ |
ざっと比較表を見るとalembicが圧倒的ですね。
実際Flaskによく使われるFlask-migrationもalembicをwrapしたものであり、Flaskに次ぐ軽量フレームワークのFastAPIも公式はalembicを推奨しています(https://fastapi.tiangolo.com/ja/tutorial/sql-databases/#alembic-note)
現時点においてはalembicとsimple-db-migrateが二大勢力といった感じでしょうか。
ですのでこの記事では主要な二つのPython Migration Toolであるalembicとsimple-db-migrateを比較していこうと思います!
それではまずalembicから使い方とメリデメを見ていきましょう!
alembic
Alembic is a database migrations tool written by the author of SQLAlchemy.
とGithubのREADMEに書いてあるとおり、sqlalchemyの作者が作っただけあってsqlalchemyとの互換性は抜群です。
autogenerateという機能を備え、sqlalchemyで定義したschemaから自動でMigration scriptを作成できます。
基本的な使い方
install
pip install alembic
(適宜使っているpackage管理ツールに置き換えてください)
alembic環境構築
alembicはテンプレートの中から目的にあった設定ファイルをサクッと作ることができます。
$ alembic list_templates
Available templates:
generic - Generic single-database configuration.
multidb - Rudimentary multi-database configuration.
pylons - Configuration that reads from a Pylons project environment.
Templates are used via the 'init' command, e.g.:
alembic init --template pylons ./scripts
マイグレーションファイルの作成
基本的な作成方法は以下のコマンドを打って作成されるファイルにPythonまたはRawSQLでスクリプトを追加していくことです。
$ alembic revision -m "Add a column"
Generating /path/to/yourapp/alembic/versions/ae1027a6acf_add_a_column.py...
done
"""Add a column
Revision ID: ae1027a6acf
Revises: 1975ea83b712
Create Date: 2011-11-08 12:37:36.714947
"""
# revision identifiers, used by Alembic.
revision = 'ae1027a6acf'
down_revision = '1975ea83b712'
from alembic import op
import sqlalchemy as sa
def upgrade():
# Migration適応内容記入
# 例 op.add_column('account', sa.Column('last_transaction_date', sa.DateTime))
def downgrade():
# rollback時適応内容記入
# 例 op.drop_column('account', 'last_transaction_date')
しかしこのような使い方をしているのではalembicの恩恵を十分に受けられません。
alembic最大の強みはsqlalchemyで定義したモデルschemaを元に自動でMigration Scriptを生成してくれることです!
Auto generate機能
Auto generate機能を使うにはデフォルトで作成されたenv.py
ファイルの中身を以下のように変更する必要があります。
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = None
from myapp.mymodel import Base (sqlalchemyで定義したモデルからdeclarative_baseをimport)
target_metadata = Base.metadata
変更後--autogenerateをつけるだけでmodel schemaを元に自動でMigration Scriptが作成されます!
$ alembic revision --autogenerate -m "Added account table"
INFO [alembic.context] Detected added table 'account'
Generating /path/to/foo/alembic/versions/27c6a30d7c24.py...done
"""empty message
Revision ID: 27c6a30d7c24
Revises: None
Create Date: 2011-11-08 11:40:27.089406
"""
# revision identifiers, used by Alembic.
revision = '27c6a30d7c24'
down_revision = None
from alembic import op
import sqlalchemy as sa
def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.create_table(
'account',
sa.Column('id', sa.Integer()),
sa.Column('name', sa.String(length=50), nullable=False),
sa.Column('description', sa.VARCHAR(200)),
sa.Column('last_transaction_date', sa.DateTime()),
sa.PrimaryKeyConstraint('id')
)
### end Alembic commands ###
def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_table("account")
### end Alembic commands ###
Auto generate...強力ですね!
自分も最初使った時は思わず「alembic様、天才!」と声をあげそうになりました。
こうして作られたMigration scriptを実行していきましょう。
マイグレーションの実行
alembic upgrade head
このコマンド一発でDBにMigration Scriptが実行されます。
DBを見てみるとalembic_version
と言うテーブルが作られており、version_num
というカラムの中に最後に当てられたMigration fileのrevisionが保存されます。
この値を元にalembicはバージョン管理をし、rollbackを可能にしています。
rollbackをするには
alembic downgrade -1
で一つ前のmigrationを取り消すことができ、複数前のrevisionまでrollbackするには、
alembic history
でrevision情報を表示し、戻りたいrevisionを指定し
alembic downgrade {revision}
で遡ることができます。
以上が基本的な使い方ですが他の機能も紹介しておきたいと思います。
tips
メリット
メリットとしては以下の点があげられます。
-
sqlalchemyで定義したschemaからmigration scriptを自動生成するauto generate機能
-
複数DB接続 / 環境によってDBを切り替えられる
-
Python、Raw SQLの両方でMigration scriptをかける
-
Communityが大きい/SQLAlchemyの作者がContributeしていることから今後も機能拡張される
デメリット
一番の欠点はautogenerateと言う素晴らしい機能を備えていますが、必ずしも万能ではないことです。
Auto generateで検知できない変更として以下の点があります。
- テーブル名の変更(drop/addになりデータが初期化されます)
- カラム名の変更(drop/addになりデータが初期化されます)
- 名前の付いていないユニーク制約 (変更を検知するにはユニーク制約に名前をつけることは必須(e.g.
UniqueConstraint('col1', 'col2', name="my_name")
) - EnumなどのSQLAlchemy特有のカラムの変更
- Columnの順番の指定
What does Autogenerate Detect (and what does it not detect?)
なので運用方法としては基本的にはauto generate、うまく生成されない場合は自分でマニュアルで記入する対応が必要になりそうです。
simple-db-migrate
simple-db-migrate is damn simple. The best way to understand how it works is by installing and using it.
続いてsimple-db-migrateを試してみましょう。
simple-db-migrateはその名の通りめちゃめちゃシンプルなMigration Toolです。
基本的な使い方
install
$ pip install simple-db-migrate
設定ファイルの作成
$ touch simple-db-migrate.conf
DATABASE_HOST = "localhost"
DATABASE_USER = "root"
DATABASE_PASSWORD = ""
DATABASE_NAME = "migration_example"
DATABASE_MIGRATIONS_DIR = "."
準備は上記のような設定ファイルを作成するだけです!
とってもSimple!
マイグレーションファイルを作成する
$ db-migrate --create {Migration名(e.g. create_table_users)}
マイグレーションを実行する
$ db-migrate
以上です!
簡単にマイグレーションを実行することができました。
実行するとDB内に__db_version__
と言う名前のテーブルが作られversion管理されるようになっていきます。
--config, ---envオプションにより環境ごとに切り替えられ--migrationオプションにより指定のrevisionまでrollbackできます。
tips
メリット
- 複数DB / envに対応している
- simpleで導入が簡単
simple-db-migrationの一番のメリットはそのシンプルさ、導入の容易さですね!
デメリット
- RawSQLしか使えない
- MySQLしか対応していない
- Auto generateのような機能はない
#まとめ
sqlalchemyと高い互換性を誇りautogenerateのような画期的な機能をもつalembicと、できる限りsimpleにバージョン管理を実現するsimple-db-migrationを比較してみました。
個人的にはalembicのauto generationがEnumのサポート、Column Orderの指定ができない点が少し残念に感じました。
autogenerateでなんでも変更検知されるはず、と思い込んでいると思わぬ事故を招きそうですね...
simple-db-migrationはその点、流すスクリプトもRawSQLでできることに制約はなく、最低限の機能は揃っているので実運用だとこちらに軍配があがる気がしました。(ただしMySQLを使用している場合に限りますが)
もしalembicのautogenerateの制約でワークアラウンド等ありましたら、コメント頂けるとありがたいです。(alembicのドキュメント量すごすぎて理解が追いついていない部分もあるかと思うので...)