MySQLのReplace構文はAUTO_INCREMENTカラムがサロゲートキーの場合、利用しない方が良い

MySQL徹底入門 第4版の第3章を読み、MySQLにReplace構文があることを学んだのでアウトプットしておく。

Replace構文 は、INSERTと似た挙動をする。

しかし、UNIQUE インデックスがついている時、古い行を削除し新しい行をInsertするという注意するべき挙動がある。

この挙動は、サロゲートキーを設定している時に問題になる。以下は、実験コードだ。

replace into user (name, email) values ("hoge", "taro@example.com"); を実行した時、id が 11から12になっている。

mysql> create table user (id int auto_increment primary key, name varchar(255) not null, email varchar(255) not null unique key);


mysql> INSERT INTO `user` (`name`,`email`) VALUES ("Alec","nostra.per.inceptos@aliquet.net"),("Myles","libero.mauris.aliquam@tristiquepharetra.edu"),("Damian","dictum@necluctusfelis.co.uk"),("Baker","Curabitur.consequat@enimNunc.edu"),("Alvin","eget@magnaPhasellus.org"),("Fulton","adipiscing@feugiatplaceratvelit.com"),("Malachi","ultrices.Duis@est.org"),("Vernon","arcu@porttitor.edu"),("Carl","Etiam.ligula.tortor@auctor.ca"),("Gray","Suspendisse@diamdictum.ca");

mysql> replace into user (email) values ("hoge@example.com");

mysql> select * from user;
+----+---------+---------------------------------------------+
| id | name    | email                                       |
+----+---------+---------------------------------------------+
|  1 | Alec    | nostra.per.inceptos@aliquet.net             |
|  2 | Myles   | libero.mauris.aliquam@tristiquepharetra.edu |
|  3 | Damian  | dictum@necluctusfelis.co.uk                 |
|  4 | Baker   | Curabitur.consequat@enimNunc.edu            |
|  5 | Alvin   | eget@magnaPhasellus.org                     |
|  6 | Fulton  | adipiscing@feugiatplaceratvelit.com         |
|  7 | Malachi | ultrices.Duis@est.org                       |
|  8 | Vernon  | arcu@porttitor.edu                          |
|  9 | Carl    | Etiam.ligula.tortor@auctor.ca               |
| 10 | Gray    | Suspendisse@diamdictum.ca                   |
| 11 | taro    | taro@example.com                            |
+----+---------+---------------------------------------------+

mysql> replace into user (name, email) values ("hoge", "taro@example.com");

mysql> select * from user;
+----+---------+---------------------------------------------+
| id | name    | email                                       |
+----+---------+---------------------------------------------+
|  1 | Alec    | nostra.per.inceptos@aliquet.net             |
|  2 | Myles   | libero.mauris.aliquam@tristiquepharetra.edu |
|  3 | Damian  | dictum@necluctusfelis.co.uk                 |
|  4 | Baker   | Curabitur.consequat@enimNunc.edu            |
|  5 | Alvin   | eget@magnaPhasellus.org                     |
|  6 | Fulton  | adipiscing@feugiatplaceratvelit.com         |
|  7 | Malachi | ultrices.Duis@est.org                       |
|  8 | Vernon  | arcu@porttitor.edu                          |
|  9 | Carl    | Etiam.ligula.tortor@auctor.ca               |
| 10 | Gray    | Suspendisse@diamdictum.ca                   |
| 12 | hoge    | taro@example.com                            |
+----+---------+---------------------------------------------+

感想

Railsで開発をしている時に、上記挙動を知っていないと取り返しのつかないデータ破損に繋がるため注意して開発したい。