UUIDやULIDは、分散システムやデータベースにおいて「一意なID」を払い出すための仕組みである。一見似たような形式だが、標準化の有無や格納効率、人間の可読性、情報露出リスクといった点で差異がある。以下に、代表的な三方式 ― UUID v4UUID v7ULID ― を中心に、特徴と選定指針を整理し、最後にUUID v1 / v6の補足も記載。

各IDの生成及び時刻情報の復元に対応したブラウザ内処理で完結するツールはこちら。


UUID v4:完全ランダム型

UUID v4は128bitのうち122bitを乱数に割き、衝突確率が極小であることを強みとする。その反面、時系列順に並ばないため、B-Tree系インデックスではページ分割が頻発し、挿入局所性が悪化しやすい。セッションIDやワンタイムキーなど「完全ランダムで良い」用途に適している。


UUID v7:時系列ソート可能な正統進化

2024年にRFC 9562で標準化されたUUID v7は、**先頭48bitにUNIXエポック時刻(ミリ秒)**を持ち、残りは乱数で埋める。辞書順(文字列比較)=生成順(時系列)となるため、主キーにしてもインデックス局所性が良い。既存のuuid型やBINARY(16)にそのまま格納できる点も強みである。

  • 乱数ビット長について:v7は内部的にversion/variantの数ビットを除き、概ね**~74bit程度が乱数として使われる。実装によりモノトニック生成**(同一ミリ秒内の衝突回避)で乱数の一部を再調整することがあるが、統計的ランダム性は十分である。
  • 情報露出リスク:IDから生成時刻(ms精度)が推定可能である。発行量が多く、乱数実装が弱い場合は近傍IDの推測が相対的に容易になる可能性がある。内部システムでは一般に許容可能だが、公開エンドポイントで連番的露出を嫌う場合は注意すべきである。

ULID:人間に優しいID

ULIDは2016年に提案されたde facto標準で、Crockford Base32の26文字で表記する。誤読しやすい文字(O/I/L/1)を除外し、URL埋め込みやコピーに強い。またUUID v7と同様、**先頭48bitに時刻(ms)**を持つため、文字列の辞書順=時系列順となる。

  • ソート保証:ULIDのBase32文字列同士の辞書順比較は常に時系列順である(モノトニック生成の仕様も広く普及している)。
  • 格納形態:TEXT(26)で可読性を取りやすい一方、DBでのバイナリ格納にはBase32↔16B変換が必要になる。128bit幅のバイナリとして扱えるが、RDBのUUID専用型には非互換であることが多い。
  • 情報露出リスク:v7同様、時刻(ms)が露出する。公開APIのリソースIDなどで「発行順を悟られたくない」場合は慎重に判断する。

三方式の比較表(実務観点)

項目 UUID v4 UUID v7 ULID
標準化 RFC 4122 RFC 9562(2024) 非標準(de facto)
ビット構成 128bit中 122bit乱数 48bit=UNIX ms + 残り乱数(モノトニック可) 48bit=UNIX ms + 80bit乱数
乱数エントロピー ≈122bit ≈74bit(version/variantを除く概算) 80bit
文字列表記 36文字(16進+ハイフン) 36文字(16進+ハイフン) 26文字(Crockford Base32)
自然ソート(テキスト) ×(ランダム) ○(辞書順=時系列) ○(辞書順=時系列)
自然ソート(バイナリ) × ○(BINARY(16)のmemcmpで昇順) ○(6B時刻を先頭ビッグエンディアンであればmemcmpで昇順)
DB格納の素性 uuid型 / BINARY(16)が最適 uuid型 / BINARY(16)が最適 TEXT(26)で可読性、BINARY(16)は変換必要 / UUID型には非互換
インデックス局所性 悪い(ランダム挿入で分割) 良い(末尾追記/ホットスポット注意) 良い(末尾追記/ホットスポット注意)
等値検索コスト 低い(16B比較) 低い(16B比較) TEXTはやや高い(collation影響)/BINARYは低い
エンコード負荷 16進↔16B(軽い) 16進↔16B(軽い) Base32↔16B(やや重い)
人間可読性/URL適性
情報露出(生成時刻) なし あり(ms) あり(ms)
主な用途 セッションID、ワンタイムキー DB主キー、イベントID、ログ時系列 URL・公開ID、ログの可視性

補足(v7/ULIDのホットスポット):単一のシャード/単一リーダーに対し末尾追記が集中すると、B-Treeの末端がホットになり得る。対策として、上位ビットの小さなシャッフル(“prefix shuffle”)シャーディングキー併用を検討する。


DB実装メモ(PostgreSQL / MySQL / SQLite)

  • PostgreSQL
    • v4/v7:uuid型が最適。v7は文字列→uuidで投入すればソート性を享受できる。
    • ULID:char(26)/textまたはbytea(16)(Base32変換)で扱う。
  • MySQL/InnoDB
    • BINARY(16)が高速で省スペース(v4/v7)。v7はビッグエンディアン配置のまま比較で時系列順になる。ULIDはCHAR(26)またはBINARY(16)+変換。
  • SQLite
    • 専用UUID型はない。BLOB(16)またはTEXTで運用する。インデックス済みBLOBは比較的効率が良い。

セキュリティ観点の補強

  • 推測耐性:v7/ULIDは時刻ビットが共通であるため、同ミリ秒内に大量発行する場合、乱数実装が弱いと近傍ID推測のリスクが相対的に上がる。暗号学的PRNGを用い、モノトニック増分の偏りを最小化する。
  • メタデータ漏洩:IDから生成時刻や大まかな発行量が類推されうる。公開APIでは内部IDと外部公開IDを分離する設計が堅実である。

まとめ(選定指針)

  • UUID v4:完全ランダム。ソート性はない。回避できない衝突リスクは理論上わずかに存在。セッションIDやCSRFトークンなどに適する。
  • UUID v7:標準化された順序付きUUID。内部システムやDB主キーに最適。モノトニック生成により衝突リスクは実用上回避可能。
  • ULID:(他に比べれば多少は)人間フレンドリー。URLやログの可視性が重要なら有力だが、内部の主キー用途ではv7に劣ることが多い。モノトニック生成により衝突リスクは実用上回避可能。

補足:UUID v1 / v6(簡潔)

  • UUID v1(タイムベース+MAC)
    60bitのタイムスタンプ(100ns単位)+ノード識別子(しばしばMACアドレス)を含む。高い時系列性があるが、MAC由来でホスト情報が露出する懸念があり、クロック逆転時の扱いなど実装注意点が多い。現代ではプライバシー上の理由から推奨されないことが多い。

  • UUID v6(v1の並び替え版)
    v1のタイムスタンプをビッグエンディアンに再配置して辞書順ソート性を高めた案。歴史的には「ソートしやすいv1」として注目されたが、標準化はv7に収束した。新規設計ではv6よりv7を選ぶのが一般的である。


付録:実装時のチェックリスト

  • 乱数は暗号学的PRNG(OS提供の安全なソース)を使う。
  • v7/ULIDのモノトニック生成は同ミリ秒内の衝突を避けつつ、乱数偏りを抑える。
  • DBはuuid型/BINARY(16)を優先し、文字列カラムのcollationに起因する性能劣化を避ける。
  • 外部公開IDのポリシー(順序露出の可否)を決める。必要に応じて内部IDと外部IDを分離する。

結論としては現状技術的には内部主キーはUUID v7を第一候補とし、可読性が重要な外部向けや技術的制約等が存在する場合はULIDも検討候補という住み分けが基本か。特殊要件(時刻露出禁止など)がある場合のみ、v4や別方式を選択することになろう。