UUIDの小ネタ・実務Tips
UUIDを採用するときは、重複しにくさだけでなく、並べ替え方や保存先も考えると判断しやすくなります。基本の構造はUUIDとは?で説明しています。
衝突確率の目安
独立で均一な乱数から作るUUIDv4を想定します。122ビットの候補からn個生成したとき、少なくとも1組が重複する確率は、小さい確率の範囲で p ≈ n(n−1) / (2 × 2^122) です。特定の2個だけが一致する確率とは異なります。
生成件数ごとの計算
| 生成件数 | 衝突確率(近似) |
|---|---|
| 10^6 | 9.4 × 10^-26 |
| 10^9 | 9.4 × 10^-20 |
| 10^12 | 9.4 × 10^-14 |
重複に備える
- DBのユニーク制約で重複を検出し、衝突時の再生成・再試行を設計します。制約自体がIDを生成するわけではありません。
- 乱数の偏りや同じ値の使い回しがあると、この計算は当てはまりません。文字列を途中で切ると候補数も減ります。
時系列性と類似フォーマット
UUIDv7は2024年5月のRFC 9562で標準化されています。ULIDとKSUIDは別形式で、UUIDの入力欄にそのまま渡すことはできません。
サイズと構造
| 形式 | 構造 | 文字列表記 |
|---|---|---|
| UUIDv4 | 128ビット(乱数122ビット) | 16進数とハイフンで36文字 |
| UUIDv7 | 128ビット。先頭48ビットがUnix時刻(ミリ秒) | 16進数とハイフンで36文字 |
| ULID | 128ビット=時刻48+乱数80 | Crockford Base32で26文字 |
| KSUID | 160ビット=時刻32+乱数128 | Base62で27文字 |
順序と互換性を確認する
- UUIDv7の残り74ビットは乱数が基本で、実装により一部を細かい時刻やカウンターに使えます。同一ミリ秒内や時計が戻った場合の順序は、ライブラリの仕様を確認します。
- ULIDも同一ミリ秒内の生成順を常に保証するわけではありません。単調増加モードは別途確認します。KSUIDの時刻は独自の起点を持つ秒単位です。
- 複数端末の時計はずれます。時刻を含むIDだけで、全端末の処理順やDBへの確定順を証明することはできません。
- GUIDはUUIDの別名として使われます。ただしバイナリ連携では、Microsoftの一部の形式とネットワークバイト順の違いに注意します。
表記と保存形式
見た目の短さと情報量は別です。復元できる符号化と、文字を削る切り詰めを区別しましょう。
表記をそろえる
- 通常表記は8-4-4-4-12桁の16進数です。大文字と小文字は同じ値を表します。ハイフンなしを受け付けるかは入力仕様で決めます。
- URNでは先頭にurn:uuid:を付けます。別のBase32・Base64url表記を採用するときは、文字集合・パディング・バイト順・元の128ビットを保つことを決めます。
保存形式を選ぶ
- DBにUUID専用型があれば候補にし、なければ16バイトのバイナリや文字列を検討します。BINARY(16)なら必ず速い、とは限りません。実際の索引・照合・クエリで比較します。
- 変換関数がUUIDv1向けにバイトを並べ替える場合があります。v7に流用する前に、往復変換とソート順を確かめます。
プライバシーと乱数品質
識別子を知っていることと、アクセスする権限があることは別です。
情報の露出を把握する
- UUIDv1は時刻を含み、実装によってはMACアドレスも含みます。ランダムなノード値にしても時刻は隠れません。UUIDv7・ULID・KSUIDも時刻を含みます。
- 乱数ベースのIDは、暗号学的に安全な乱数生成器を使うライブラリで生成します。UUIDを秘密のアクセス権として扱わず、認証・認可を別に実装します。
入力の検証
「UUIDらしい文字列」と「そのAPIが受け付けるUUID」を分けて確認します。
受け付ける形式を決める
- パーサーで構造を検査し、APIが許可するバージョンとバリアントを確認します。バージョンは第3ブロックの先頭です。NilやMaxを許すかも用途ごとに決めます。
- 構造が正しくても、レコードの存在や閲覧権限までは保証しません。保存時の一意性と、アクセス時の認可をそれぞれ確認します。
UUIDv4を生成する
Python 3または対応するNode.jsがインストールされた端末で実行します。Pythonのコマンド名がpython3の環境では読み替えてください。
Pythonで生成する
python -c "import uuid; print(uuid.uuid4())"
Node.jsで生成する
crypto.randomUUID対応版を使います。毎回異なる値が出ます。
node -e "console.log(require('node:crypto').randomUUID())"
仕様と関連記事
RFC 9562 (§4, §5.4, §5.7, §6, §8) / ULID specification / KSUID reference implementation / Python uuid / Node.js crypto.randomUUID