Posted at

中途半端なマイグレーション

More than 3 years have passed since last update.

Railsで使うデータベースはマイグレーションで組み立てていきますが、状況によってはマイグレーションに失敗して、マイグレーション前でもマイグレーション後でもない闇に落ちていってしまうことがあります。


MySQLの特性

マイグレーションの実行に失敗した場合、Railsは今までにした操作をロールバックして、マイグレーション前の状態に戻ろうとします。これはPostgreSQLやSQLiteの場合なら無事ロールバックできるのですが、MySQLの場合、CREATE TABLEALTER TABLEを実行すると強制的にトランザクション外となってしまうため、成功した操作をロールバックすることもできず、中途半端な状態のDBができあがってしまいます。


失敗例

マイグレーションに失敗する例としては、


  • 列名の間違い(すでにある列を追加しようとした、ない列を削除しようとした、ない列にインデックスを張ろうとしたなど)

  • すでにあるものと同名のテーブルやインデックスを追加しようとした

  • 単純な書き間違い1

などミスが大半ですが、人間はミスをするものである以上、根絶することは難しいです。


予防策

予防策としてはいくつか考えられますが、副作用もあります。


  • そもそもMySQLではなく、DDLもロールバックできるDBエンジンを使う(これだけで選ぶほど大きな問題ではない)

  • 1つのマイグレーションで1つの書き換えだけ行なって、中途半端な状態を作らせない(マイグレーションが増える)

  • 先にテスト環境でマイグレーションを流して、ちゃんと通ってから開発・本番などに持っていく


脱出方法

では、不幸にしてマイグレーションの狭間に落ちてしまった場合は、どうすればいいのでしょうか。この場合、状況としては


  • マイグレーションの進捗状況の記録(schema_migrations)…前のマイグレーションまで実行

  • DBの状態…最新のマイグレーションの途中

ということになっています。手法としては、以下のいくつかが考えられます。


  1. DBを直接叩いてマイグレーション前の状態に戻して、(誤記は修正して)もう一度rake db:migrate

  2. マイグレーションファイルから成功した分以外を消しておいて、schema_migrationsに手で追加、そして残りは別のマイグレーションに回す

  3. マイグレーションファイルの中で成功した分ををコメントアウトしてrake db:migrate、終了後にコメントアウトを戻す

  4. 手作業でDBとschema_migrationsを整え、成功したことにしてしまう

個人的には、(特段の事情がなければ)1がいいかなと考えています。





  1. 一回、remove_indexdrop_indexと書いてしまって動かない、ということがありました。