テーブルを作るとき、主キー戦略を選びます —— そしてこの決定は思いのほか影響が大きいものです。最もよくある選択は連番整数と UUID の 2 つ。両者の比較と使い分けを見ていきましょう。
連番整数
BIGINT AUTO_INCREMENT(Postgres の SERIAL)のような列は、行が挿入されるたびに 1、2、3… と払い出します。
利点:コンパクト(4〜8 バイト)、人間が読める、自然に順序付き、そしてインデックス局所性が優れている —— 新しい行は B-tree の末尾に追加され、挿入が高速です。
欠点:情報が漏れる(競合が /users/5000 を見れば規模がわかる)、推測可能(認可が甘いと列挙攻撃を許す)、そして分散・シャーディング環境で扱いにくい —— 2 つのノードが協調なしに次の番号を独立して発行できないためです。
UUID
UUID は 550e8400-e29b-41d4-a716-446655440000 のような 128 ビットの識別子です。v4 は乱数なので、どのノードも協調なしに生成でき、衝突リスクは実質ゼロ。データベース往復の前にクライアント側で作ることもできます。UUID ジェネレーターでまとめて生成すると形式がわかります。
利点:協調なしで全世界的に一意、件数が漏れない、推測不可、データベース間でマージ可能。
欠点:大きい(16 バイト、テキストなら 36 文字)、人に優しくない、そして重要なのは —— ランダムな UUIDv4 はインデックス局所性を損なうこと。新しいキーが B-tree のあちこちにランダムに落ちるため、挿入でページ分割が起き、インデックスが断片化して大きなテーブルで書き込みが遅くなります。
中間解:UUIDv7 / ULID
「どこでも一意」と「インデックスに優しい」のどちらかを選ぶ必要はありません。時刻順の ID、すなわち UUIDv7 や ULID はタイムスタンプの接頭辞を埋め込むため、全世界的に一意でかつほぼ順序付き —— UUID の分散フレンドリーさを保ちつつインデックス局所性を回復します。UUID の利点を書き込みペナルティなしで得たい新規システムでは、これが既定になりつつあります。
選び方
- 小規模・単一 DB・内部 ID? 連番はシンプルで速い。
- 公開する ID、または規模を隠したい? UUID(あるいは対外は UUID、内部は整数キーを保持)。
- 分散・シャーディング・クライアント生成 ID? UUID —— インデックス性能のため理想は UUIDv7/ULID。
- 連番 ID をセキュリティに頼らないこと。キーがどれだけ推測しやすくても、認可は必ず実施しましょう。
ひとことまとめ
連番はシンプルさと生のインデックス性能で勝り、UUID は一意性・プライバシー・分散で勝ります。両取りしたいなら時刻順の UUIDv7/ULID を。
今すぐ識別子が必要?無料の UUID ジェネレーターがブラウザで RFC 4122 v4 ID を生成 —— まとめて生成し、ワンクリックでコピーできます。