UUID v4 と v7 の違い、いつどちらを使うべきか

約6分

UUID(Universally Unique Identifier)は、システム間で衝突しない識別子を生成するための標準規格です。長らく v4(ランダム)が事実上のデフォルトでしたが、2024 年に RFC 9562 が公開されて v7 が正式なバージョンとして加わり、選択肢が増えました。本記事では v4 と v7 の構造的な違いと、用途による使い分けを整理します。

UUID 全体の構造

すべての UUID は 128 bit(16 バイト)のデータで、文字列表現は 32 桁の16進数を 8-4-4-4-12 の形でハイフン区切りにしたものです。

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
         ↑    ↑    ↑
         |    |    └─ variant(上位ビットでフォーマット種別を表す)
         |    └────── version(v1 / v4 / v7 など)
         └─────────── version 依存のデータ

M 位置の最初の桁が version を示し、N 位置の上位ビットが variant を示します。同じ128 bit でもバージョンごとに残りビットの意味が違うのがポイントです。

v4:完全ランダム

v4 は名前の通り、version と variant の固定ビットを除いた 122 bit を暗号学的乱数で埋めたものです。

6e8b3c1d-4f2a-4b9d-8c1e-5a7f9d2b4c6e
                ↑    ↑
              version=4
                     variant

特徴:

  • 生成が単純:暗号乱数生成器を呼ぶだけ
  • 推測困難:URL に埋め込んでも他のレコードを推測できない(/api/orders/<uuid> のような ID として安全)
  • 時系列情報を持たない:いつ生成されたかは UUID 自体からは分からない
  • 衝突確率は実質ゼロ:122 bit のランダムなので、誕生日のパラドックスを考慮しても実用上衝突しない

長らくこの「単純さ+安全性」の組み合わせで標準的な選択肢として使われてきました。

v7:時刻ベース+ランダム

v7 は 先頭 48 bit に Unix ミリ秒タイムスタンプを入れ、残りをランダムビットで埋める設計です。

01970000-0000-7xxx-Nxxx-xxxxxxxxxxxx
└──────┬──────┘   ↑    ↑
   48 bit ms      version=7
                       variant + 74 bit ランダム

特徴:

  • 時系列順にソート可能:UUID 文字列を辞書順にソートすると生成時刻順になる
  • インデックス効率が良い:データベースで主キーに使うとき、新しいレコードが常にインデックスの末尾に追加されるためページの分散が起きにくい
  • 時刻情報を含む:ID から生成時刻が逆算できる(プライバシー上は v4 より弱い)
  • 同一ミリ秒内の衝突対策:実装によっては末尾ランダム部にカウンタを入れて単調増加性を担保する

主キーとして使うときの差:B-Tree インデックスの効率

v4 と v7 の最大の実務的な差は、B-Tree インデックスでの挙動です。多くの RDB(PostgreSQL, MySQL/InnoDB など)は主キーを B-Tree で管理し、新しいキーは B-Tree のどこかに挿入されます。

v4 を主キーにすると

ランダムなキーは B-Tree のランダムな位置に挿入されます。これにより:

  • 既存ページが満杯のときにページ分割が頻発する
  • ホットなページがランダムに点在し、バッファプールのキャッシュ効率が悪化する
  • 大量のレコードを連続挿入するワークロードで顕著に遅くなる

v7 を主キーにすると

時刻順なので、新しいキーは常に B-Tree の末尾に追加されます:

  • ページ分割がほぼ起きない(末尾ページに追加されるだけ)
  • 直近のレコードが連続したページに集中し、キャッシュ効率が良い
  • 自動採番の整数主キーに近いインデックス効率が得られる

ベンチマークでは、書き込み主体のワークロードで v7 が v4 より数倍速いケースもあります。

推測困難性のトレードオフ

v7 は「いつ生成されたか」が UUID 自体から分かるため、情報漏洩のリスクが v4 より高いです。

例えば公開 URL に /orders/<uuid-v7>/ を使うと、攻撃者は ID から「いつ作られた注文か」を推測できます。これが業務上問題になる場合:

  • v7 の時刻精度を意図的に粗くする(秒単位に丸めるなど)
  • 外部公開する ID は別途 v4 や短いランダム文字列を生成する
  • そもそも順序付けが不要なら v4 のままで十分

順序保証が要らないユースケース(外部公開トークン、API キーの一部など)は v4 のほうが安全です。

使い分けのまとめ

ユースケース推奨理由
主キー(書き込み多い)v7インデックス効率
主キー(書き込み少ない)v4 でも v7 でも可性能差が出にくい
公開 URL の IDv4推測困難性
外部 API のリクエスト IDv4 / v7 どちらも可用途次第
イベントログの IDv7時系列ソートが効く
認証トークンどちらも非推奨UUID は秘密鍵向けではない、専用の乱数生成を使う

言語/ランタイム側のサポート状況

2026 年時点で v7 のネイティブサポートは:

  • Node.jscrypto.randomUUID() は v4 を返す。v7 は uuid パッケージや独自実装を使う
  • Python:標準 uuid モジュールは v1〜v5 のみ。v7 は uuid7 パッケージなど
  • PostgreSQLuuid_generate_v7() 拡張または gen_random_uuid() の v7 化を待つ状況
  • MySQL:標準には未対応、UUID_TO_BIN を使った代替実装が一般的

新規プロジェクトで主キーに使うなら v7 の採用を検討する価値があります。本サイトの UUID 生成ツールでも v4 と v7 の両方を生成できるので、どちらの形式かサンプルを比較したいときに使えます。