ID 体系の選び方:UUID v4 / v7・ULID・NanoID・Snowflake をユースケースで使い分ける

約9分

「テーブルの主キーを自動採番にするか、ULID にするか」「短縮 URL の ID をどう作るか」「複数サーバで衝突しない ID が要る」——いずれも ID 体系の選定です。本記事では現在現実的な 5 つの選択肢(UUID v4、UUID v7、ULID、NanoID、Snowflake)を、特性の比較と選定フローで整理します。

比較表

形式長さエンコード時刻情報ソート可能衝突確率主なユースケース
UUID v436(hex)hex + ハイフンなし不可122bit ランダム匿名性が要る ID、汎用
UUID v736(hex)hex + ハイフン48bit ms74bit ランダムDB 主キー、ログ ID
ULID26(Crockford Base32)Base3248bit ms80bit ランダムDB 主キー、URL に含めるID
NanoID21(任意)URL-safe Base64なし不可約 126bit ランダム短縮 URL、外部公開トークン
Snowflake19 桁の数値64bit 整数41bit ms22bit (worker+seq)数値主キーが必要な分散システム

時刻でソートしたいか」「長さの制約があるか」「数値カラムに入れたいか」が主な分岐点です。

UUID v4:匿名性とランダム性が最優先

crypto.randomUUID() で生成、122 bit のランダム。

  • 生成順序の情報が一切漏れない
  • どの言語・どの DB でもネイティブサポート
  • データベースの B-tree インデックスではランダム性が裏目に出る:挿入順序がランダムなのでページ分割が頻発し、書き込みパフォーマンスが落ちる

UUID v4 をそのまま主キーにすると、書き込みの多いテーブルで顕著にスループットが落ちることがあります。「Postgres で UUID 主キーが遅い」という議論は大抵 v4 を指しています。

UUID v7:時刻順 + 標準仕様

RFC 9562(2024 年に発行)で正式化された新バージョン。

  • 上位 48 bit がミリ秒タイムスタンプ
  • 下位は 74 bit のランダム
  • 文字列としても、バイナリとしてもソート可能
  • v4 と同じ 36 文字フォーマットなので、UUID カラムをそのまま使える

DB 主キーとしての性能問題(ランダム挿入によるページ分割)が解決されており、新規プロジェクトの主キーは v7 が第一候補になりつつあります。クライアント側で生成しても、クライアントのクロックがそこそこ正しければ DB の挿入順は時刻順になります。

v4 → v7 への移行の罠

既存テーブルで UUID カラムが既に v4 の値で埋まっているところに v7 を混ぜてもソート性は復活しない。混在させるなら、新規行は v7、既存は v4 のまま、検索時には作成日時カラムを別途持つのが現実的。

ULID:UUID より短く、人にも読める

26 文字の Crockford Base32 で表現されます(例:01ARZ3NDEKTSV4RRFFQ69G5FAV)。

  • 上位 48 bit ms タイムスタンプ + 下位 80 bit ランダム(仕様は UUID v7 と似ている)
  • アルファベットが I/L/O/U を意図的に除外しており、人間が打ち間違えにくい
  • URL に直接含められる(記号なし)

UUID v7 と思想は近いが、表現が違う。文字数は 36 vs 26 で ULID のほうが短い。一方、UUID v7 はバイナリとしての標準があり、DB の uuid 型が使える分、運用上の互換性は UUID 系が上。

ULID と UUID v7、結局どちらにすべきか

  • すでに UUID 型が運用されている / 将来も DB のネイティブ UUID 型を使いたい → UUID v7
  • ID を URL や CLI 引数に直接見せる、人がコピペすることがある → ULID
  • バイナリで保存サイズを最小化したい(16 byte vs 任意バイト) → UUID v7

NanoID:短い・URL セーフ・カスタマイズ可能

デフォルト 21 文字、URL セーフな 64 文字アルファベット (A-Z a-z 0-9 _ -) のランダム生成。

  • UUID とほぼ同等の衝突確率を 21 文字で達成
  • 長さもアルファベットも変えられる(短くしたいなら 12 文字、人に読ませるなら大文字を抜く、など)
  • 時刻情報は持たない

短縮 URL や外部公開する外向きのトークンに向きます。「UUID は長すぎる、でもセキュアな ID が欲しい」用途。

NanoID の長さは何文字あれば十分か

衝突確率は誕生日問題で計算できます。21 文字(126 bit のエントロピー)なら、毎秒 1000 個生成しても衝突するのに数十億年。実用上、外部公開 ID として 21 文字あれば足ります。逆に内部 ID であれば短くできる:1000 万件で衝突確率 0.0001% を狙うなら 12 文字程度。

Snowflake:64 bit 数値が要るとき

Twitter が公開した分散 ID 採番方式。

  • 41 bit ミリ秒タイムスタンプ + 10 bit ワーカーID + 12 bit シーケンス = 64 bit
  • 数値(BIGINT)一発で済む
  • 時刻順にソート可能

Snowflake が向く状況

  • 数値 ID が DB スキーマで要求されている(古いシステムとの互換、JOIN の高速化)
  • 採番サーバを集中で持たず、ワーカーごとに自律的に採番したい
  • ID をクライアントに見せても問題ない(時刻が漏れる)

Snowflake の罠

  • ワーカーID の重複は致命的。複数ノードに同じ ID を割り当てると衝突が始まる
  • 12 bit シーケンスは 1 ms あたり 4096 個まで。それを超える勢いで採番するワーカーは、シーケンスを使い切ったときに 1ms 待つ実装が標準
  • クライアント側で生成する場合、ワーカーID を乱数にすると衝突が確率的に発生する。サーバー間で割り当てを協調できる環境向け

選定フロー

新規システムで ID 体系を決めるとき、以下の順で絞れます。

  1. 数値カラムにしか入れられない(古い RDB 互換、JOIN 性能要件)か?

    • YES → Snowflake
    • NO → 次へ
  2. 時刻でソートしたい(DB 主キー、ログ)か?

    • YES → UUID v7(互換性重視)/ULID(短さ・可読性重視)
    • NO → 次へ
  3. 生成元が秘密にしたい(生成時刻すら漏らしたくない)か?

    • YES → UUID v4 か NanoID
    • NO → 戻って 2 を再検討
  4. 長さの制約がきつい(URL 短縮・QR・SMS)か?

    • YES → NanoID(21 文字 or それ以下)/ULID(26 文字)
    • NO → UUID 系

用途ごとの推奨(早見表)

  • DB 主キー(新規) → UUID v7
  • DB 主キー(数値必須) → Snowflake
  • 外部公開する短縮 URL → NanoID(12〜16 文字)
  • 匿名性が要る共有リンク → UUID v4 か NanoID
  • CLI で人がコピペする ID → ULID(紛らわしい文字を回避済み)
  • ログ・トレース ID → UUID v7 か ULID

まとめ

UUID v4 一択の時代は終わりつつあります。書き込みが多い主キーは v7 か ULID外部公開する短いトークンは NanoID数値カラムが要れば Snowflake、というのが 2026 年現在の標準的な分業です。

各形式の生成は ULID / NanoID / Snowflake 生成ツール で試せます。UUID v4 / v7 は UUID 生成ツール を使ってください。