LoginSignup
0
0

More than 3 years have passed since last update.

MySQL5.7 で AUTO_INCREMENT の値が突然 1に戻る怪奇現象を追ってみた。

Last updated at Posted at 2020-04-14

KT3WlrL_bsg.jpg

実装中に奇妙なことが起きました。
ローカルの開発環境内で構築した MySQL5.7での出来事です。

AUTO_INCREMENTを設定したidを持つテーブルに、INSERT処理を実行しました。
すると、100近くまでカウントされていたidが突然1に戻っていたんです。
そのテーブルは他のテーブルとの関係を多く持っており、これ本番(AWS RDS)もバグっちゃうのでは!?と焦り散らかしましたが、過去そのような事例は起きてなかったみたいなんです。

ガクブルの僕は恐る恐る調査を始めることにしました。

■発生条件の調査

どのタイミングで発生するのだろう。全く予想できない。
約20個近くあるテーブル全てにAUTO_INCREMENTを設定したidが存在するのですが、毎度 1にリセットされてしまうテーブルは決まって1つのテーブルのみ。

何が他のテーブルと違うかなーと考えた時に、1点大きな違いがありました。
それは、 「データ削除の方法」 です。

基本的には「論理削除」を採用しているのですが、とても流動性が高いテーブルだったので、どうやらこのテーブルだけは 「物理削除」 を採用しています。

僕「まさか、、、こいつが関係しているのか?」

いやでも待てよと。何のための AUTO_INCREMENTなんだいと。
その辺を自動で採番してくれるから便利なんだろ AUTO_INCREMENTさんよぉ と。

正直この疑惑は信じたくなかったです。一気にAUTO_INCREMENTの信用が下がってしまうじゃないかと。
でも違いがこれしかないんです。そこで僕はようやく Google先生に力を借り始めました。

■原因究明

検索ワード:mysql autoincrement id リセット

ほとんどが 「AUTO_INCREMENTをリセットする方法」 という検索結果の中、輝く一件を見つけました。

スクリーンショット 2020-04-14 21.44.57.png

僕「ピンポイントすぎるうぅぅぅぅ!!」

真っ白に輝くこちらの記事。僕が求めていた内容が載っていました。

こちらの記事を見てみると、

MySQLが再起動されると連番の一番大きい値にカウンターがリセットされるという実装になっています。
つまり、最大値のレコードが物理削除された後に再起動されると、その値が再度使用されてしまうということです。AUTO INCREMENTカウンターをシーケンスであると完全に信頼して設計していたので、拍子抜けしましたし、実装を理解せずに使用して恥ずかしいです。

、、、嘘でしょ?
信じたくなかったことが起きました。やはり物理削除がAUTO_INCREMENTに大きく関係していました。

再起動をするたびに、AUTO_INCREMENTは連番の最大値にカウンターがリセットされていたんです。
ということは、 もしも物理削除を実施してすっからかんになったテーブルのAUTO_INCREMENTカウンターが「100」だったとしても、MySQLを再起動するとそのテーブルには1件レコードは入っていないので、「1」からスタートしてしまう ということです。

■対策

こちらの記事に掲載されている対策として、3つ紹介がありました。

  1. MySQL8へのバージョンアップ
  2. 論理削除にする
  3. 採番用のテーブルを作る

この3つの中でどれを採用しようかというところなのですが、私が関わっているサービスは、つい先日ローンチしたばかりです。
この初期段階でMySQLのバージョンアップは提案しづらいというのと、まだまだissueが残っているなかで採番用のテーブルを用意して、約20近くのテーブル群の採番を一つにまとめるのも重たいかなと感じました。

そのため、今回はそのテーブルを物理削除から論理削除に切り替えて、その周辺の処理を修正することになりました。(バグも少なそうだし)

■まとめ

  • 新規開発するなら、MySQL8を採用しようね。
  • もしもMySQL5系を採用した新規開発をするなら、AUTO_INCREMENTには十分気をつけて、設計段階でシーケンステーブルを用意しようね。
  • とはいえやっぱり物理削除って本当に怖いから、論理削除を採用しようね。
  • 「まっしろブログ」さんの記事が的確すぎて本当に感謝だね。(以下の参考文献にリンク貼ってますので、そちらも是非)

■追記

書き洩れましたが、なぜ本番環境(AWS RDS)で起きていないかというと、可能性が2点あります。
1. 常に最新の一件が存在した時に再起動が実行されていた。
2. 再起動が実施されなかった。

1 は、神的すぎるタイミングなので、おそらく可能性は薄いかと。
2 は、可能性高いです。
https://go-journey.club/archives/9869
こちらの記事によると、数ヶ月に一回セキュリティパッチの適用があって、自動アップデートが走っちゃうこともあるみたいなのですが、まだそれに当たっていないだけかと。。。
遅かれ早かれ起きていたことなので、ローンチしてすぐ発覚してよかった。。。

■参考文献

https://masshiro.blog/mysql-auto_increment-reset/
https://go-journey.club/archives/9869

0
0
0

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
0
0