Slide 1

Slide 1 text

AUTO_INCREMENTのIDカラムが オーバーフローしたらどうなるの? 
 〜実例から学ぶ DB設計の注意点〜 
 NE株式会社
 やまもとひろや
 PHPerKaigi2025 登壇資料


Slide 2

Slide 2 text

自己紹介
 ● やまもとひろや
 ● NE株式会社 開発部マネージャー
 ● X: @HiroyaYamamoto1
 ● Qiita: @yamamoto_hiroya
 ● Zenn: yamamoto_hiroya
 ● 今回NE株式会社は4名登壇!
 ● 新卒採用もやってるので是非!
 ○ https://ne-inc.jp/recruit
 ○ 「NE株 採用」で検索!


Slide 3

Slide 3 text

突然ですが 
 2147483647
 これ何の数字か分かりますか? 


Slide 4

Slide 4 text

そうですね! 
 INT型の最大値ですね! 
 (2^31-1)


Slide 5

Slide 5 text

4294967295
 は分かりますか? 


Slide 6

Slide 6 text

そうですね! 
 符号なし(UNSIGNED)
 INT型の最大値ですね! 


Slide 7

Slide 7 text

今回は実際に 
 UNSIGNED INTのIDカラムが
 上限を超えた 
 弊社事例を紹介します! 


Slide 8

Slide 8 text

目次
 ● INT型(UNSIGNED INT)とは
 ● 実際に起きた弊社事例
 ● 対応方法と学び
 ● まとめ


Slide 9

Slide 9 text

● 今回はMySQLのINT型に絞ってお話しします。
 参照: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
 INT型(UNSIGNED INT)とは


Slide 10

Slide 10 text

INT型(UNSIGNED INT)とは
 普通のINT
 (符号あり)
 UNSIGNED INT
 (符号なし)
 ● 数値を入れるためのデータ型です。
 ● 赤い部分がそれぞれの範囲です。
 ● 通常のINTがマイナス値入るの忘れがち。
 ● UNSIGNEDはマイナス値入らない=符号なしとも呼ぶ
 ● 自分用: INTは約21億、符号なしは約43億
 0
 -2147483647
 4294967295
 2147483647


Slide 11

Slide 11 text

実際に弊社で起きた事例 
 調査担当
 私
 以下エラーが出ているんですがどういう状況 か分かります?
 Duplicate entry '4294967295' for key 'sample_table.PRIMARY'


Slide 12

Slide 12 text

ふむふむ
 どうやらsample_tableのPRIMARYの
 カラム(ID)が4294967295を書き込もうとし てエラーになっているみたいだね。
 Duplicateなので既にそのID値は存在して いるみたい。
 実際に弊社で起きた事例 
 調査担当
 私


Slide 13

Slide 13 text

実際に弊社で起きた事例 
 調査担当
 私
 じゃあIDが4294967295のレコードが
 悪さをしてそうだから
 調査してレコード削除等をすれば
 いいですかね?


Slide 14

Slide 14 text

ん〜というか
 4294967295はUNSIGNED INTの最大値 だから
 これもしかしてレコード上限
 来ちゃってるかもね
 実際に弊社で起きた事例 
 調査担当
 私


Slide 15

Slide 15 text

実際に弊社で起きた事例 
 調査担当
 私
 え?
 UNSIGNED INTがオーバーフローすると Duplicateエラーになるんですか?


Slide 16

Slide 16 text

実際に弊社で起きた事例 
 ● ある日突然以下のエラーが発生しました。
 ● Duplicate entry '4294967295' for key 'sample_table.PRIMARY'
 ● データの書き込みが全て止まった。


Slide 17

Slide 17 text

再現テスト 
 ● 状況をローカル環境にて再現しました。
 ● テーブル定義は以下のものを使います。
 ● データは以下のようにします。


Slide 18

Slide 18 text

● この状態で新規レコードを追加しようとするとDuplicateエラーが再現し ました。
 再現テスト 


Slide 19

Slide 19 text

● 以下のような挙動をします。
 ● ID値が4294967295になった。
 ● 次の処理でAUTO_INCREMENTのためIDを+1しようとしたが最大値のた め4294967295のままになった。
 ● IDのカラムはPRIMARYのため重複できない。
 ● そのため4294967295を再びINSERTしようとしてDuplicateエラーとなっ た。
 ● 補足: 現在のauto_increment値の
 確認方法
 ● SHOW TABLE STATUS LIKE 
 'sample_table';
 解説


Slide 20

Slide 20 text

調査担当
 私
 レコードの削除をしてauto_incrementの値 をリセットする?
 どう対処したか 
 約43億のレコード削除はだいぶ時間がかか るので今回は難しそう。


Slide 21

Slide 21 text

調査担当
 私
 INT型を変えて桁数増やす?
 どう対処したか 
 ALTERにだいぶ時間がかかるので今回は難 しそう。


Slide 22

Slide 22 text

調査担当
 私
 今のsample_tableをsample_table_oldと し、新しくsample_tableを作成する?
 どう対処したか 
 RENAMEも新しいsample_table作成もサ クッとできる。作ったらすぐそのテーブルにレ コードが書き込まれ始める。
 よし、これで行こう!


Slide 23

Slide 23 text

解決!


Slide 24

Slide 24 text

補足
 ● ちなみに今回の例はサービス開始し約5年で発生しました。
 ○ 1日235万レコードペース
 ● そもそもそんな大量のデータをデータベースに持ちたいか?という観点か ら注意が必要です。
 ● どうしても持つ場合はBIGINTで持つと2^63乗まで持てます(約900京)
 ○ 例えばこれを10年で使い切るには1日250兆のレコードが入り続ける必要があり、ほぼ使 い切らないくらい大きい上限値だと思ってもらって良いと思います。 
 ○ もしBIGINTを使い切ったよっていうご経験がある方がいたら是非教えてください。 


Slide 25

Slide 25 text

学び
 ● AUTO_INCREMENTで
 ● PRIMARYの
 ● INT型の
 ● ID値が
 ● 上限に行くと
 ● Duplicateエラーとなる。


Slide 26

Slide 26 text

まとめ
 ● 安易なID値設計は辞めましょう。
 ○ デフォルトのINT型AUTO_INCREMENT, PRIMARYで本当に大丈夫か?
 ● そもそもそのIDカラムは必要か?
 ○ サロゲートキーか?ナチュラルキーか? 
 ● 全て考えてIDカラムを持つとして、ものすごいレコードが入る場合は BIGINTにしましょう。
 ● そのテーブルは
 ● 「どういう使われ方をするのか」
 ● 「どういうデータが入るのか」
 ● 「どれくらいの頻度で入るのか」
 ● これらを考えて適切なテーブル設計をしていきましょう!


Slide 27

Slide 27 text

No content