サービスが成長してテーブルが肥大化してくるとインデックスの追加などを気軽に行うことができなくなってきます。alter tableするためにメンテナンスの時間を取ることもできますが、無停止で変更できるならそれに越したことはありません。
この記事では、Railsで開発されているWebサービスでそういったことを実現するための方法を紹介します。
tl;dr
- Railsのmigrationを使うのではなく、無停止で
alter table
するための専用のツールを使いましょう。 -
alter table
したら、整合性が取れるように修正しましょう。
この記事に書かないこと
oak-online-alter-tableやpt-online-schema-changeの細かい使い方については説明しません。どちらも公式ドキュメントが充実していますし、説明している良記事がWebにあるので、そちらを参照してください。
方針
Railsのプロジェクトは内部的に schema_migrations
というテーブルを用意して、そこに実行済みのmigrationファイルのタイムスタンプを入れています。 rake db:migrate
ではこのテーブルに 無い migrationファイルを実行したのちに、そのタイムスタンプをテーブルに追加します。
なので、手動で rake db:migrate
を実行する代わりに、手動でmigrationファイル相当の処理を実行したのちに、対応するタイムスタンプを schema_migrations
に追加すれば、あたかもRailsのmigration機能を使ったかのごとくDBに手を加えることができます。
流れ
- migrationファイルを書く
- developmentで
rake db:migrate
実行する。 - productionにツールを使って
alter table
を実行する - productionの
schema_migrations
に1で作ったmigrationファイルのタイムスタンプを追加する
migrationファイルを書く
まずは何はともあれmigrationファイルを書きます。ここでは仮に users
テーブルの name
カラムにインデックスを追加するものとします。
class AddIndexToUsers < ActiveRecord::Migration
def change
add_index :users, [:name]
end
end
developmentでdb:migrateを実行する
migrationファイルができたら、これもいつも通りdevelopment環境で rake db:migrate
を実行します。これはdb/schema.rbを更新するために行います。
ここまでやったらgit的にはコミットしてしまって問題ありませんが、この状態でデプロイすると通常通りのmigrationが走ってしまうので絶対にデプロイしてはいけません。
productionにツールを使ってalter tableを実行する
世の中には大きなテーブルに alter table
を実行するためのツールがいくつか存在するのでそれを使います。
あたりが有名ドコロです。詳しい使い方はググッてください。
productionのschema_migrationsにタイムスタンプを追加する
schema_migrations
にタイムスタンプを追加します。タイムスタンプというのはmigrationファイルの先頭にある数字の部分のことで、今回はファイル名が "20160407191432_add_index_to_users.rb" なので、タイムスタンプは "20160407191432" になります。