activerecord-import の on_duplicate_key_update, on_duplicate_key_ignore 周りを調査
背景
activerecord-importのバージョンを0.15.0から1.2.0(最新)にアップデートしたい。 on_duplicate_key_update周りでBREAKING_CHANGEがある。 DBはMySQLを使用している。
on_duplicate_key_updateとは
MySQL
https://dev.mysql.com/doc/refman/5.6/ja/insert-on-duplicate.html
UNIQUEインデックスまたはPRIMARY KEYが重複するKeyを持つ(つまりduplicate keyな)行が挿入された場合に、どのカラムを更新するか指定できる。
activerecord-import
https://github.com/zdennis/activerecord-import/#duplicate-key-update
MySQL, PostgreSQL (9.5+), and SQLite (3.24.0+) support on duplicate key update (also known as "upsert") which allows you to specify fields whose values should be updated if a primary or unique key constraint is violated.
BREAKING_CHANGE
Previously :on_duplicate_key_update was enabled by default for MySQL. The update timestamp columns (updated_at, updated_on) would be updated on duplicate key. This was behavior is inconsistent with the other database adapters and could also be considered surprising. Going forward it must be explicitly enabled. See #548.
今まではon_duplicate_key_updateオプションにデフォルトでupdated_atが入っていたが、アップデートでそれが無くなる。
実装
- https://github.com/zdennis/activerecord-import/blob/v0.15.0/lib/activerecord-import/import.rb#L105-L110
- https://github.com/zdennis/activerecord-import/blob/v0.15.0/lib/activerecord-import/import.rb#L653
- https://github.com/zdennis/activerecord-import/blob/v0.15.0/lib/activerecord-import/adapters/mysql_adapter.rb#L72
on_duplicate_key_ignoreとは
https://github.com/zdennis/activerecord-import/#duplicate-key-ignore
MySQL, SQLite, and PostgreSQL (9.5+) support on_duplicate_key_ignore which allows you to skip records if a primary or unique key constraint is violated. MySQL it uses INSERT IGNORE
duplicate keyな行が挿入された場合に、レコードの更新をしないためのオプション。
https://dev.mysql.com/doc/refman/5.6/ja/insert.html
IGNORE キーワードを使用した場合、INSERT ステートメントの実行中に発生したエラーは無視されます。たとえば、IGNORE を使用しない場合は、テーブル内の既存の UNIQUE インデックスまたは PRIMARY KEY 値を複製する行によって重複キーエラーが発生し、このステートメントは中止されます。IGNORE を指定すると、その行が破棄され、エラーは発生しません。代わりに、無視されたエラーが警告を生成する可能性がありますが、重複キーエラーは生成しません。
エラーを抑制するオプションで、エラーに気付くづらくなるというデメリットがあるため、基本的には指定しないほうが良さそう。
not null制約に関するエラーも無視するっぽい https://stackoverflow.com/a/548570
Inserting a NULL into a column with a NOT NULL constraint.
調査
duplicate keyなレコードをimportしたときにどのようにupdateされるか調査。
ver 0.15.0
on_duplicate_key_update を指定しない場合
updated_atだけ更新されている。
on_duplicate_key_update[:name] を指定した場合
nameとupdated_atが更新されている。
allオプションを指定した場合
ver 0.15.0では指定できなかった。0.26.0からは使えそう。
ver 1.2.0
on_duplicate_key_update を指定しない場合
Duplicate entryエラーがでた。内部的にはINSERTしているだけだから当然か。
on_duplicate_key_update([:name]) を指定した場合
nameとupdated_atが更新された。 updated_atは指定しなくても更新されるっぽい。
on_duplicate_key_update([:updated_at]) を指定した場合
nameは更新されず、updated_atだけ更新される。