テーブルを作るとき、主キー戦略を選びます —— そしてこの決定は思いのほか影響が大きいものです。最もよくある選択は連番整数と UUID の 2 つ。両者の比較と使い分けを見ていきましょう。
1000 個生成して確認しました。 UUID ジェネレーターで 5 回に分けて 1000 個:ユニーク 1000/1000 —— 衝突 0 件、1000 件すべてバージョン nibble が
4、1000 件すべて RFC の variant 範囲、いずれもちょうど 36 文字。最後の数字がこのページの本題です。36 文字対 8 バイト整数、しかもすべての外部キーとインデックス項目で繰り返されます。UUID が買うのは「クライアント側で生成でき、調整が不要」なこと。支払うのはストレージとインデックスの局所性です。
連番整数
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 のあちこちにランダムに落ちるため、挿入でページ分割が起き、インデックスが断片化して大きなテーブルで書き込みが遅くなります。
衝突の議論はふつう確率表で行われます。私たちは代わりに計測しました。私たちの UUID ジェネレーターで 200 個の識別子を 5 回生成し、その 1000 個の値のうち衝突は 0 件 —— 1000 個が一意でした。すべてバージョン数字が 4(1000/1000)で、すべて 36 文字(1000/1000)でした。これは一意性の証明ではありません。122 ビット空間から 1000 回引いて衝突するほうが難しい。ただし実務で本当に壊れる 2 点は検証できます。弱い乱数源へ黙って退避するジェネレーターと、長さやバージョンニブルを誤るジェネレーターです。
中間解:UUIDv7 / ULID
「どこでも一意」と「インデックスに優しい」のどちらかを選ぶ必要はありません。時刻順の ID、すなわち UUIDv7 や ULID はタイムスタンプの接頭辞を埋め込むため、全世界的に一意でかつほぼ順序付き —— UUID の分散フレンドリーさを保ちつつインデックス局所性を回復します。UUID の利点を書き込みペナルティなしで得たい新規システムでは、これが既定になりつつあります。
選び方
- 小規模・単一 DB・内部 ID? 連番はシンプルで速い。
- 公開する ID、または規模を隠したい? UUID(あるいは対外は UUID、内部は整数キーを保持)。
- 分散・シャーディング・クライアント生成 ID? UUID —— インデックス性能のため理想は UUIDv7/ULID。
- 連番 ID をセキュリティに頼らないこと。キーがどれだけ推測しやすくても、認可は必ず実施しましょう。
コスト側も同じく測れますし、選択がひっくり返るのはたいていここです。あの 1000 文字はテキストとして 36 バイト、整数の 4 または 8 バイトに対して。しかも順序がないため、挿入は末尾ではなく B-tree インデックスのランダムな位置に落ちます。それが本当の取引です。0 件の衝突を、インデックスの局所性という代価で買っている —— まさに UUIDv7 と ULID がそれを返すために設計されたものです。
ひとことまとめ
連番はシンプルさと生のインデックス性能で勝り、UUID は一意性・プライバシー・分散で勝ります。両取りしたいなら時刻順の UUIDv7/ULID を。
今すぐ識別子が必要?無料の UUID ジェネレーターがブラウザで RFC 4122 v4 ID を生成 —— まとめて生成し、ワンクリックでコピーできます。