UUID v4の衝突確率
UUID v4の衝突確率を徹底解説。誕生日のパラドックスに基づく数学的計算、具体的な数値、122ビットの乱数が衝突を事実上不可能にする理由を説明します。
詳細な説明
UUID v4の衝突確率はUUIDに関する最もよくある質問の一つです。結論から言えば、実際のアプリケーションで2つの同一UUID v4が生成されるよりも、隕石に当たる確率のほうが高いです。
計算の背景: UUID v4は122ビットのランダムビット(128ビットからバージョン4ビットとバリアント2ビットを除く)を持ち、2^122 = 5.316 x 10^36個の値が存在します。衝突確率は誕生日のパラドックスの公式に従います:
P(collision) ≈ 1 - e^(-n² / (2 * 2^122))
ここで n は生成されたUUIDの数です。
具体的な数値:
| 生成UUID数 | 衝突確率 |
|---|---|
| 100万 | 5.3 x 10^24分の1 |
| 10億 | 5.3 x 10^18分の1 |
| 1兆 | 5.3 x 10^12分の1 |
| 2.71 x 10^18 | 50%(誕生日の限界値) |
| 1京(10^15) | 5.3 x 10^6分の1 |
衝突確率が50%に達するには、約2.71 x 10^18(2.71エクサ)個のUUIDが必要です。地球上のすべての人が毎秒1つのUUIDを生成した場合、この数に到達するまで約11年かかります。
衝突が報告される理由: 開発者がUUIDの「衝突」を報告する場合、原因はほぼ以下のいずれかです:
- 不適切な乱数生成器:
crypto.getRandomValues()の代わりにMath.random()を使用。JavaScriptのMath.random()は暗号論的に安全ではなく、一部の実装では短い周期を持ちます。 - コピペのバグ: 同じUUIDがコードやデータ内で誤って複製された。
- データベース移行エラー: データインポート時にUUIDが誤って再利用された。
- VMのクローン: スナップショットからクローンされた仮想マシンが同じ乱数シードの状態を共有し、同一のシーケンスが生成された。
エッジケースへの対策:
// WRONG: Uses Math.random(), can produce predictable sequences
function badUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = Math.random() * 16 | 0;
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
// RIGHT: Uses cryptographic randomness
function goodUuid() {
return crypto.randomUUID();
}
データベースレベルの保護: 衝突は事実上不可能ですが、UUIDカラムには必ずUNIQUE制約を追加してください。ごくわずかなパフォーマンスコストで安全ネットを提供し、UUID生成ロジックのバグを検出できます。
ストレージ規模の文脈: 地球上のすべてのコンピューターがこれまでに生成したすべてのUUIDを合計しても、2^122個の可能な値と比較して無限に小さな数です。UUID v4の空間は実用的にはすべての目的において枯渇不可能です。
ユースケース
衝突確率の理解は、独立してUUIDを生成する分散システムの設計時に重要です。通常の運用ではUNIQUE制約違反が発生しないことを数学的に保証します。