AUTO_INCREMENTはINSERTするたびにカウントアップして発番してくれるが、ON DUPLICATE KEY UPDATEを使用してINSERTではなく既存行のUPDATEになった場合もカウントアップされてしまう。実際にINSERTしている行数はたいしたことがないのに、ON DUPLICATE KEY UPDATEされる回数が多いせいで、AUTO_INCREMENT値が大きくなってしまい、INTなどの比較的小さい型にしていた場合にAUTO_INCREMENTが上限値に達してしまう。
以下のテーブルをもとにINSERTされていないのにAUTO_INCREMENT値が増えていることを実際に確認する。
mysql> CREATE TABLE on_dup_autoinc (id INT AUTO_INCREMENT PRIMARY KEY, ukey CHAR(1) UNIQUE KEY, cnt INT DEFAULT 1);
Query OK, 0 rows affected (0.01 sec)
mysql> DESC on_dup_autoinc;
+-------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| ukey | char(1) | YES | UNI | NULL | |
| cnt | int(11) | YES | | 1 | |
+-------+---------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
AUTO_INCREMENTの初期値はデフォルトの1となっている。
mysql> pager grep Auto_increment
PAGER set to 'grep Auto_increment'
mysql> SHOW TABLE STATUS LIKE 'on_dup_autoinc'\G
Auto_increment: 1
1 row in set (0.00 sec)
mysql> nopager
PAGER set to stdout
まずはテーブルにデータを2件登録する。すると想定通り次に採番される値は3になる。
mysql> INSERT INTO on_dup_autoinc(ukey) VALUES('A');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO on_dup_autoinc(ukey) VALUES('B');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM on_dup_autoinc;
+----+------+------+
| id | ukey | cnt |
+----+------+------+
| 1 | A | 1 |
| 2 | B | 1 |
+----+------+------+
2 rows in set (0.00 sec)
mysql> pager grep Auto_increment
PAGER set to 'grep Auto_increment'
mysql> SHOW TABLE STATUS LIKE 'on_dup_autoinc'\G
Auto_increment: 3
1 row in set (0.00 sec)
mysql> nopager
PAGER set to stdout
ここで既にあるukey = 'A'のデータを再度INSERTする。既にあるので、ON DUPLICATE KEY UPDATE句が適用されて、cntが現在の値 + 1 となる。
mysql> INSERT INTO on_dup_autoinc(ukey) VALUES('A') ON DUPLICATE KEY UPDATE cnt = cnt + 1;
Query OK, 2 rows affected (0.01 sec)
mysql> SELECT * FROM on_dup_autoinc;
+----+------+------+
| id | ukey | cnt |
+----+------+------+
| 1 | A | 2 |
| 2 | B | 1 |
+----+------+------+
2 rows in set (0.00 sec)
INSERTされていないのでAUTO_INCREMENT値が3のままかと思いきや、カウントアップされて4になっている。
mysql> pager grep Auto_increment
PAGER set to 'grep Auto_increment'
mysql> SHOW TABLE STATUS LIKE 'on_dup_autoinc'\G
Auto_increment: 4
1 row in set (0.00 sec)
mysql> nopager
PAGER set to stdout
実際に存在しないukeyをINSERTしてみると、idが4で発番されて、3が欠番になっている。
mysql> INSERT INTO on_dup_autoinc(ukey) VALUES('C') ON DUPLICATE KEY UPDATE cnt = cnt + 1;
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM on_dup_autoinc;
+----+------+------+
| id | ukey | cnt |
+----+------+------+
| 1 | A | 2 |
| 2 | B | 1 |
| 4 | C | 1 |
+----+------+------+
3 rows in set (0.00 sec)