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をすすめるのはこのへんに理由があるのかな。