dbスキーマもバージョン管理したい!
DESCRIPTION
PostgreSQLカンファレンス2013 LightningTalk (2013-11-13: migr8.rbの設定箇所を若干修正) (2013-11-14: SQLite3での設定等を修正、「migr8.rb new --table=users」を追加)TRANSCRIPT
![Page 1: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/1.jpg)
DBスキーマもバージョン管理したい!—省略してない版—
Makoto Kuwata <[email protected]>http://www.kuwata-lab.com/
PostgreSQLカンファレンス2013 LightningTalk
更新履歴:・2013-11-13 migr8.rbの設定における若干の間違いを修正・2013-11-14 SQLite3での設定等を修正、「migr8.rb new --table=users」を追加
![Page 2: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/2.jpg)
背景✓ ソースコードのバージョン管理は普及してる
Git、Mercurial、Subversion、…
✓ 対して、DBスキーマのバージョン管理は…
そもそも存在を知らない人が多い
![Page 3: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/3.jpg)
OT: 控え室にてQ: PostgreSQL界隈では、スキーマのバージョン管理では何が人気なんですか?
A: そんなものはない
達人のお墨付き!!
(石井さんごめんなさい)
![Page 4: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/4.jpg)
発表のゴール✓ DBスキーマもバージョン管理できることを知ってもらう・サンプルその1:Ruby on Rails (DSL派)
・サンプルその2:Migr8.rb (SQL派)
✓ バージョン管理ツールの選択ポイントを紹介・DSL vs. SQL
・バージョン番号の採番方法
![Page 5: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/5.jpg)
用語解説:「マイグレーション」✓ DBMS自体を変更すること例:OracleからPostgreSQLにマイグレーションした
✓ DBMSのバージョンを更新すること例:PosrgreSQLを8.4から9.3にマイグレーションした
✓ DBスキーマのバージョンを更新すること例:テーブル追加したのでマイグレーションを実行してね
ここではこの意味で使う
![Page 6: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/6.jpg)
はじめてのDBスキーマ管理Ruby on Rails 編(DSL派)
![Page 7: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/7.jpg)
Ruby on Rails とは?✓ Ruby製の超人気フレームワーク
http://rubyonrails.org/
✓ マイグレーション機能をいち早く搭載他のフレームワークがこぞって真似することに
→ Railsのやり方を知れば、他もだいたい同じ
![Page 8: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/8.jpg)
マイグレーションファイルを作成$ rails generate migration CreateUsers$ ls db/migrate/20131104023129_create_users.rb
バージョン番号としてタイムスタンプを使う
![Page 9: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/9.jpg)
DBスキーマの変更操作を記述## 20131104023129_create_users.rbclass CreateUsers < ActiveRecord::Migration def up create_table "users" do ¦t¦ t.string "name" t.string "email" end end def down drop_table "users" endend
バージョンを上げるときの操作
バージョンを戻すときの操作
![Page 10: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/10.jpg)
DBスキーマの変更操作を記述## 20131104023129_create_users.rbclass CreateUsers < ActiveRecord::Migration def change create_table "users" do ¦t¦ t.string "name" t.string "email" end endend
簡単な操作なら、戻すときの操作を省略可能(Railsが推測してくれる)
![Page 11: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/11.jpg)
マイグレーションを実行### バージョンを上げる$ rake db:migrate
### バージョンを戻す$ rake db:rollback
### 再実行(戻して、もう一度上げる)$ rake db:migrate:redo
### 現在のバージョンを調べる$ rake db:versionCurrent version: 20131104023129
![Page 12: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/12.jpg)
実行結果を確認postgres=> \dt users; List of relations Schema ¦ Name ¦ Type ¦ Owner--------+-------+-------+-------- public ¦ users ¦ table ¦ myname(1 row)
テーブルが作成されたことを確認
postgres=> select * from schema_migrations; version---------------- 20131104023129(1 row)
バージョン番号が専用のテーブルに保存される
![Page 13: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/13.jpg)
管理サイクルStep 1. マイグレーションファイルを作成
Step 2. 変更操作を手動で記述 ・バージョンを上げるときの操作 ・バージョンを戻すときの操作
Step 3. マイグレーションを実行 ・DBスキーマが変更される ・現在のバージョン番号がDB内に保存される
これらの手順の積み重ねでバージョン管理を行う(この手順から外れた方法で変更しないこと!)
![Page 14: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/14.jpg)
ソースコード管理ツールとの違いGit、Subversion
※ 支援機能を持つツールもあるが、あくまで「支援」だけ
・差分は「データ」(diff形式)
・ツールが自動計算
@@ -1,4 +1,5 @@ #include <stdio.h>-void main() {+int main() { printf("Hello");+ return 0; }
スキーマ管理ツール・差分は「操作」(DSL or SQL)
・人が手動で記述
def change create table "users" t.string "name" t.string "email" ... endend
※
@@ -1,4 +1,5 @@ #include <stdio.h>-void main() {+int main() { printf("Hello");+ return 0; }
@@ -1,4 +1,5 @@ #include <stdio.h>-void main() {+int main() { printf("Hello");+ return 0; }
@@ -1,4 +1,5 @@ #include <stdio.h>-void main() {+int main() { printf("Hello");+ return 0; }
@@ -1,4 +1,5 @@ #include <stdio.h>-void main() {+int main() { printf("Hello");+ return 0; }
![Page 15: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/15.jpg)
はじめてのDBスキーマ管理Migr8.rb 編(SQL派)
![Page 16: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/16.jpg)
Migr8.rb(マイグレイト.rb)とは?✓ お手軽なDBスキーマ管理ツール・PostgreSQL、SQLite3、MySQLをサポート・要Ruby
・https://github.com/kwatch/migr8
✓ 使うまでのしきいが低い・ファイル1つだけ(他の余計な外部ライブラリが不要)・設定ファイルがない(環境変数を2つ設定するだけ)・SQLで記述(DSLの学習コストがかからない)
※
※ 実は、自作ツール :)
![Page 17: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/17.jpg)
インストールとセットアップ
$ curl -Lo migr8.rb http://bit.ly/migr8_rb$ chmod a+x ./migr8.rb
$ export MIGR8_COMMAND="psql -q -U user db"$ export MIGR8_EDITOR="emacsclient" # or "vi"$ ./migr8.rb init
設定ファイルがいらない
Install
Setup※
※ または export MIGR8_COMMAND="sqlite3 dbfile" (for SQLite3) export MIGR8_COMMAND="mysql -s -u user db" (for MySQL)
![Page 18: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/18.jpg)
マイグレーションファイルを作成$ migr8.rb new -m "create 'users' table" # or: migr8.rb new --table=users$ ls migr8/migrationsscjs8350.yaml
バージョン番号としてランダム文字列を使う(とても重要な特徴!)
![Page 19: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/19.jpg)
DBスキーマの変更操作を記述# -*- coding: utf-8 -*-version: scjs8350desc: create 'users' tableauthor: alicevars:
up: ¦ create table users ( id serial primary key, name varchar(255) not null unique, );
down: ¦ drop table users;
バージョンを上げるときの操作
バージョンを戻すときの操作
![Page 20: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/20.jpg)
DBスキーマの変更操作を記述# -*- coding: utf-8 -*-version: scjs8350desc: create 'users' tableauthor: alicevars: - table: users
up: ¦ create table ${table} ( id serial primary key, name varchar(255) not null unique, );down: ¦ drop table ${table};
変数を定義可能
変数を展開
変数を展開
![Page 21: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/21.jpg)
マイグレーションを実行### バージョンを上げる$ ./migr8.rb up
### バージョンを戻す$ ./migr8.rb down
### 再実行(戻して、もう一度上げる)$ ./migr8.rb redo
### 現在のバージョンを調べる$ ./migr8.rb status # 省略可...(snip)...
![Page 22: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/22.jpg)
実行結果を確認postgres=> \dt users; List of relations Schema ¦ Name ¦ Type ¦ Owner--------+-------+-------+-------- public ¦ users ¦ table ¦ myname(1 row)
テーブルが作成されたことを確認
postgres=> select * from _migr8_history; version---------- scjs8350(1 row)
バージョン番号が専用のテーブルに保存される
![Page 23: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/23.jpg)
履歴を表示$ ./migr8.rb hist
scjs8350 2013-11-07 23:01:13 # [alice] create 'users'
ewwg6691 2013-11-07 23:29:33 # [alice] add index
gnqc9473 (not applied) # [john] create 'groups'
spvo5800 (not applied) # [john] add 'group_id'
適用すべきマイグレーションの一覧
マイグレーションを適用した日時(未適用なら "(not applied)")
作成者と説明文
![Page 24: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/24.jpg)
ツール選択のポイント #1
DSL vs. SQL
![Page 25: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/25.jpg)
ORM依存
ORM独立
DSLSQLMigr8
RailsCakePHP
South
LinquibaseFlyway
Alembic
分類
Evolutions(Play Framework)
Doctrine
PHPMigrateYoyo-migrations
![Page 26: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/26.jpg)
比較✓ DSL+ORM依存 (Railsなど)
・ORMや言語を乗り換えるのは難しい
・DBMSを乗り換えたり複数種類をサポートするのは簡単
・SQLでは困難でも、RubyやPHPでなら簡単に解決できることも
✓ SQL+ORM独立 (Migr8など)
・ORMや言語の乗換えがしやすい
・DBMSの乗り換えはほぼ無理(DDLがDBMS依存なため)
・困ったときにRubyやPHPでゴニョゴニョできない
![Page 27: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/27.jpg)
どう選ぶ?✓ ORMやFWに付属している場合・それを使うしかない(DB管理者に選択権はない)
・DSLタイプでも生SQLを書ける機能はある(これが現実解?)
✓ ORMやFWに付属していない場合・ORM非依存のを推奨
・PostgreSQLもMySQLもサポートしたい!→ DSLタイプ
・DBMSの乗り換えなんてしないよね~ → 生SQLタイプでOK
![Page 28: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/28.jpg)
ツール選択のポイント #2
バージョン番号の採番方法
![Page 29: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/29.jpg)
バージョン番号に求められる性質複数人で同時に開発作業をしても、バージョン番号が重ならないでほしい(重複しては困る)
番号の順番(=マイグレーションの適用順序)は一意に決まってほしい(人や環境によって違うのは困る)
一度決めたバージョン番号は変わらないでほしい(primary keyなんだから値の変更は困る)
一意性
順序性
不変性
![Page 30: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/30.jpg)
バージョン番号の採番方法✓ 連番複数人での開発時に、番号が重複しやすい(一意性が低い)
✓ タイムスタンプ番号がそのまま順番を表すため、マイグレーションの適用順を変えたい場合、番号の変更が必要(不変性が保たれない)
✓ ランダム文字列番号は一意性のみを担保し、順序性は別の方法で保持→適用順を変更しても、番号の変更は必要ない(不変性を保持)
却下!
却下!
採用!
![Page 31: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/31.jpg)
タイムスタンプだと困るケースあるブランチで、マイグレーションを作成 別のブランチで、より
新しいタイムスタンプでマイグレーションを作成し、
先にコミットした!
すると、古いタイムスタンプのほうが、より新しいコミットになってしまう
適用順 != タイプスタンプ順 Gitのコミット
![Page 32: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/32.jpg)
ソースコード管理システムの進化
※ 正確には「コミットのハッシュ値」
Subversion(リポジトリ別の連番)
Git, Mercurial(ランダム文字列)
CVS(ファイル別の連番)
※
進化
進化
GitやMercurialの設計思想はスキーマ管理にも応用できる
![Page 33: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/33.jpg)
ランダム文字列で順序性:Alembic
revision = 'fa2cfc94fd'down_revision = '547dcd1d3c30'
def upgrade(): op.create_table('users', Column('id', Integer, primary_key=True), Column('name', String, nullable=False), )
def downgrade(): op.drop_table('users')
マイグレーションファイルに、戻り先のバージョン番号を記述(Gitのしくみとそっくり)
Alembic
![Page 34: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/34.jpg)
ランダム文字列で順序性:Migr8
# -*- coding: utf-8 -*-scjs8350 # [alice] create 'users' tableewwg6691 # [alice] add index to 'name' colgnqc9473 # [john] create 'groups' tablespvo5800 # [john] add 'group_id' to 'users'
専用のテキストファイルに、バージョン番号を順番に並べる
(マイグレーションファイルには書かない)
Migr8
![Page 35: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/35.jpg)
まとめ
![Page 36: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/36.jpg)
まとめ✓ DBスキーマのバージョン管理サイクル・Step1. マイグレーションファイルを作成
・Step2. スキーマ変更操作を記述(up, down)
・Step3. マイグレーションを実行
✓ ツール選択のポイント・DSL vs. 生SQL
・連番 vs. タイムスタンプ vs. ランダム文字列
![Page 37: DBスキーマもバージョン管理したい!](https://reader033.vdocuments.pub/reader033/viewer/2022052900/555df500d8b42ae4628b4a14/html5/thumbnails/37.jpg)
おしまい