19
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Mysql]db:migrate時にadd_indexで失敗するとハマる

Last updated at Posted at 2015-02-16

MysqlとPostgreSQLの意外な機能差

MysqlとPostgreSQLってどっちもオープンソースだし似たようなもんでしょ、と思っていたんだけど、体感できる差を知ってしまった。

Mysqlでは、トランザクションの最中にcreate indexしようとすると、その時点でcommitしてしまってトランザクションじゃなくなってしまう。

MySQL :: MySQL 5.1 リファレンスマニュアル :: 12.4.3 暗黙のコミットを引き起こすステートメント : http://ftp.nchu.edu.tw/MySQL/doc/refman/5.1/ja/implicit-commit.html

PostgreSQLはちゃんと処理してくれるらしい。
Transactional DDL in PostgreSQL: A Competitive Analysis - PostgreSQL wiki : https://wiki.postgresql.org/wiki/Transactional_DDL_in_PostgreSQL:_A_Competitive_Analysis

MySQLでTruncateはRollback出来るのか? | SRIA BLOG : http://www.sria.co.jp/blog/2014/08/mysql-can-do-rollback-truncate/

railsだと、下記のようなケースでこの差が顕在化する

add_indexのミス

Migrationを書くときに、

class CreateActionLogs < ActiveRecord::Migration
  def change
    create_table :action_logs do |t|
      t.integer :user_id
      t.string :log_type
      t.timestamps
    end
    add_index :action_logs, [:log_type, :log_type], length:64
  end
end

みたいなコードを書いたんだけど、このadd_indexの書き方はMysqlだと通らない(sqliteだと通る)
これをうっかり実行した結果、add_indexでエラーになってmigrationがとまってしまった。

mysqlでは、add_indexの手前のcreate tableの時点でコミットが行われてしまうけど、migration全体としては失敗しているので、rails的にはこのマイグレーションは実行していないものと認識される。
でも実際にはaction_logsテーブルはすでに作成されているので、add_index部分を直してdb:migrateしてもtable already existsでエラーになってしまう。
逆に、db:rollbackでaction_logsテーブルを削除しようとしても、まだ実行されていないマイグレーションと認識されるので、rollbackしてもらうことも出来ない。ハマり状態。

これがPostgreSQLだと、create tableも含めてトランザクション(DDLトランザクション)でひとまとめに扱ってくれるので、add_indexが失敗した時も、全部ロールバックしてくれるらしい。へー。

脱出方法

ちなみにこのハマり現象は、migrationファイルを一時的に書き換えてmigrateを通したあと、元に戻してrollback→migrateして正しい状態に戻すことが出来た。

class CreateActionLogs < ActiveRecord::Migration
  def change
#     いったんコメントアウトした状態でmigrateする
#    create_table :action_logs do |t|
#      t.integer :user_id
#      t.string :log_type
#      t.timestamps
#    end
    add_index :action_logs, [:log_type, :log_type], length:64
  end
end

railsのみんながMysqlじゃなくてPostgreSQLをすすめるのはこのへんに理由があるのかな。

19
26
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
26

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?