UUIDのバージョン
UUIDは128ビットの識別子で、32桁の16進数を8-4-4-4-12のグループに分けて表記し、RFC 9562で標準化されています。バージョンを示すニブルが作り方を教えてくれます。v1とv6は時計から、v3とv5は名前のハッシュから、v4は乱数から、v7はUnixタイムスタンプ+乱数から――順序付けとプライバシーのトレードオフがそれぞれ異なります。
UUIDのバージョンとは
出会ったことのない2つのシステムが、誰にも聞かずに行、リクエスト、ファイルに名前を付けたい。それがUUIDが解決する問題です。ローカルの情報――時計、ランダムビット、名前――から識別子を生成すれば、他の誰かが同じ値を生成する確率は、計画に組み込める程度には小さくなります。調整サービスも、奪い合う共有カウンターも、問い合わせる中央レジストリーも不要です。
現在の標準はRFC 9562です。2024年5月にRFC 4122の後継として発行され、目玉の変更は、v6とv7という2つの新しいバージョンに公式の地位を与えたことです。バージョンは3番目のグループの最上位ニブルに宿ります――2つ目のハイフンの直後の16進1桁です――そしてバリアントビットが4番目のグループを開きます。この2桁を読めば、UUIDの出自がひと目で分かります。
このガイドでは、各バージョンのビット構成、得意なこと、そして正直さが尽きる場所を説明します――v1が埋め込むMACアドレスのプライバシーコストも、v4の背後にある衝突の数学も含めて。下でリンクしているジェネレーターはいくつかのバージョンをローカルで生成するので、自分のマシンでパターンを確かめられます。
以下で説明する各レイアウトは、本物の標本と並べて見るのがいちばん早く分かります――UUIDジェネレーターはブラウザ内でv4とv7の識別子を生成し、生成したものがログに記録されたりどこかへ送信されたりすることは一切ありません。
識別子はトークンの中を旅することもあります。JWT構造ガイドでは、jtiクレームがUUIDを運ぶ場所と、トークン自体は署名されていても秘密ではない理由を解説しています。
解剖:36文字に収まった128ビット
UUIDは128ビットで、慣行的には32桁の小文字16進数を8-4-4-4-12の5グループにハイフンで区切って書きます――ハイフン込みで36文字、なければ32文字。この並びは飾りではありません。特定のビット範囲が意味を担います。4ビットのバージョンフィールドは3番目のグループの最上位ニブルを占め、2ビットのバリアント――RFC式UUIDを古いMicrosoft式やレガシー方式から区別するもの――は4番目のグループの最上位ビットを占め、16進では常に8、9、a、bのいずれかとして読めます。
| グループ | 桁の例 | 内容(v1の例) |
|---|---|---|
| 1 | 614e4000 | time_low――タイムスタンプの最下位ビット |
| 2 | 26bc | time_mid――タイムスタンプの中間ビット |
| 3 | 11ef | 12ビットのタイムスタンプ、続く4ビットがバージョン――1はv1を意味する |
| 4 | b17d | 2ビットのバリアント(2進で10)、続く14ビットがクロックシーケンス |
| 5 | 0242ac120002 | 48ビットのノード――v1では生成したマシンのMACアドレス |
4つのバージョン、ひと目で
v1 614e4000-26bc-11ef-b17d-0242ac120002 v4 f7b17bde-5a0c-4174-8c95-407558615543 v6 1ec9414c-232a-6b00-b3c8-9e6bdeced846 v7 019b76da-a800-7c3e-8f2a-5b6c7d8e9f0a
どこを見るか
3rd group, 1st hex digit = version (1, 4, 6, 7 here) 4th group, 1st hex digit = variant (b, 8, b, 8 here)
v1とv6:時計とMACアドレス
v1は、1582年10月15日――グレゴリオ暦の始まり――から100ナノ秒間隔を数える60ビットのタイムスタンプに、クロックシーケンスのカウンターとマシンの48ビットMACアドレスを添えて識別子を組み立てます。タイムスタンプはtime_low、time_mid、time_highと一見して分からない形に分割されています。1990年代のビット詰めの都合で選ばれ、のちに悔やまれることになったフィールド順です。MACアドレスはプライバシーの地雷です。すべてのv1 UUIDは、それを作ったハードウェアを明かします。だからこそRFC 4122は既に、ランダムなマルチキャストノードへの差し替えを認めていました。
v6は、フィールド順を正したv1です。最上位のタイムスタンプビットが先頭に移動するため、文字列としてソートすればv6 UUIDは時系列に並びます。同じ時計、同じノードフィールド、同じプライバシー上の注意点――しかしデータベースでの挙動ははるかに良好です。並べ替えの狙いはそこにすべてあります。
同じタイムスタンプ、2つのフィールド順
v1: 614e4000-26bc-11ef-b17d-0242ac120002 v6: 1ec9414c-232a-6b00-b3c8-9e6bdeced846
文字列インデックスで正しくソートされるもの
v6――timeHighフィールドが先頭にあるため、 辞書順がそのまま時系列順になる。v1は下位ビットから 始まるため、順序がばらばらになる。
v3とv5:名前から生まれる同一性
v3とv5は、名前空間UUIDと名前から識別子を導出します。ハッシュにはMD5(v3)かSHA-1(v5)を使います。同じ名前空間、同じ名前なら、同じUUID――どのマシンでも、ずっと。この決定性こそが売りです。対応表を保存しなくても、URL、ユーザー名、ドメイン名から安定した識別子を導き出し、いつでもどのシステムでも再生成できます。
代償は決定性の裏返しです。識別子は名前についての情報を漏らします。エントロピーの低い名前のv5は、単純な総当たりで確認できてしまいますし、同じ名前は意図どおり同じ識別子を生みます。v5はv3を置き換えます――SHA-1がMD5の上に立つ――ただしRFC 9562は新しい名前ベースのバージョンを名乗っていないため、決定性と時間順序の両方を求める新しい設計は、たいてい名前を脇に保存した上でv7へ移ります。
決定的:同じ入力、同じ出力
namespace: DNS 6ba7b810-9dad-11d1-80b4-00c04fd430c8 name: python.org v3 6fa459ea-ee8a-3ca4-894e-db77e160355e v5 886313e1-3b8a-5372-9b90-0c9aee199e5d
どこでも再現できる理由
hash(namespace bytes || "python.org") に、バージョン (3または5)とバリアント(2進数10)を固定の ビット位置に書き込む——ビット単位で同じ計算。
v4:122ビットの乱数と、それが買ってくれるもの
v4は、暗号学的に安全な乱数生成器から122ビットを埋めます。固定されるのはバージョンとバリアントのニブルだけです。衝突確率は誕生日の限界(birthday bound)に従います。n個生成した時点で、重複がどこかに存在する確率はおよそn²/2¹²³です。衝突1件がコイン投げと同じ確率になるには、約2^61個――ざっくり2.3×10^18個――のUUIDが必要です。実際に重複が姿を見せるとき、原因はほぼ必ず壊れた乱数です。弱いシード、使い回されたPRNGの状態、ハードウェアの故障――確率そのものでは決してありません。
乱数であることは、データベースキーとしてのv4の弱点でもあります。まったく順序づけられていない値はB-treeの無作為なページに着地し、インデックスを断片化させ、規模が大きくなると書き込みキャッシュを使い果たします。まさにこの不満を直すためにv6とv7が標準化されました。多くのORMや分散データベースが新しいテーブルをv7へ誘導するのも、同じ理由からです。
v7:Unixミリ秒プラス乱数
v7は現代の既定候補です。ミリ秒単位のUnixタイムスタンプ48ビットに、12ビットと62ビットの乱数ペイロードが続きます。先頭のタイムスタンプのおかげでv7 UUIDは文字列としてソートでき――まさにそれを保存するデータベースでインデックスに優しい――74ビットの乱数が衝突確率を実質v4並みに保ちます。MACアドレスも、1582年のエポックも、暦の変換も不要です。
同一ミリ秒の中では、RFC 9562がrand_aフィールドの単調カウンターを定めており、立て続けに作られた識別子も増加し続けます――主キーが生のユニーク性よりも強く求める性質です。タイムスタンプも読める形です。1582年からの100ナノ秒刻みの回数ではなく、2026年とそのまま読めます。ログやクエリ結果を目で追うとき、v7は心地よく出来ています。
構造そのものが時間順
2026-01-01T00:00:00Z 019b76da-a800-7c3e-8f2a-5b6c7d8e9f0a 2026-01-01T00:00:01Z 019b76da-abe8-9d41-8c2f-4a5b6c7d8e9f
文字列でソートすれば時間順
019b76da-a800-… < 019b76da-abe8-… 辞書順は時系列順と一致し、 上位48ビットはミリ秒単位のUnixタイムスタンプ。
バージョンの選び方、包み隠さず
新しい仕事への指針はこうです。識別子を時間順にソートしたい、あるいはデータベースのインデックスに住まわせるならv7。それ以外はv4――どちらも調整を必要とせず、出自について何も漏らしません。識別子を名前から再現できる必要があるなら、v5がその役を果たします。v1とv6は引き続きサポートされますが、ジェネレーターがノードフィールドをランダム化しない限りハードウェアの同一性を漏らします。v3は互換性のために持ち越されたMD5のレガシーです。どのバージョンも秘密ではありませんし、どれもデータを匿名化しません。UUIDは名前であって、資格情報ではないのです。
| バージョン | ビットの供給源 | 文字列ソート | 注意点 |
|---|---|---|---|
| v1 | グレゴリオ暦のタイムスタンプ+クロックシーケンス+MACノード | 不可 | MACアドレスの漏えい |
| v3 | 名前空間+名前のMD5 | 不可 | MD5のレガシー。名前は推測可能 |
| v4 | 122ビットの乱数 | 不可 | ランダムな挿入順がインデックスを断片化する |
| v5 | 名前空間+名前のSHA-1 | 不可 | 決定的――名前の推測で確認できてしまう |
| v6 | ソート性のために並べ替えたv1 | 可 | v1と同じMACアドレスの注意点 |
| v7 | Unixミリ秒タイムスタンプ+74ビットの乱数 | 可 | 単調カウンターがないと同一ミリ秒で同着になる |
よくある質問
このサイトで生成したUUIDはどこかに記録されますか?
いいえ。ジェネレーターは、タブの中でお使いのブラウザ自身の乱数APIを使って識別子を作ります。アップロードの段階も、サーバー側のログもありません。コードがリクエストを一切送らないからです。動いている間、Networkパネルが沈黙し続けるのを確認できますし、サイトのContent-Security-Policyはページの生存期間中ずっと外向きの接続をブロックします。
実際に2つのUUIDが衝突することはありますか?
v4では、誕生日の限界により、重複1件がコイン投げ程度の確率になるのは生成値が約2^61個――ざっくり2.3×10^18個――に達したときです。現実の衝突はほぼ必ず、不運ではなく壊れた乱数を示します。弱いシード、使い回されたPRNGの状態、ハードウェア乱数生成器の故障などです。v3とv5は意図的に「衝突」します――同じ名前空間の同じ名前は、設計上、同じUUIDを返すのです。
一部のUUIDがデータベースの主キーとしてソートに向かないのはなぜですか?
乱数バージョン(v4)は、新しい行をB-treeインデックスのあちこちに散らばらせます。予測できないページへの書き込みが続き、テーブルが育つにつれキャッシュはかき乱されます。時間順バージョン(v6、v7)は、代わりにインデックスの右端付近へ追記していきます。v4キーに固執するなら、定番の対策は、時間順のクラスタリング列を別に設けるか、新しい行をv7に移すことです。
UUIDは秘密ですか?匿名ですか?
どちらでもありません。UUIDは識別子であって資格情報ではないからです。持っている人物が誰かを証明する力を持ち合わせておらず、v1に至っては、ノードフィールドがランダム化されていない限り、生成したマシンのMACアドレスを発信します。UUIDは名前として扱ってください――ログに残して安全、照合に役立つ――そして認証と認可は、実際に何かを検証できる仕組みへ委ねましょう。
GUIDとUUIDの違いは何ですか?
同じ128ビット識別子の一族を指す別の呼び名で、GUIDはMicrosoftの用語です。技術的な違いは、4番目のグループの先頭にあるバリアントビットに宿ります。ここが、RFC式UUID(2進で10――先頭の16進桁は8、9、a、b)と、古いMicrosoft式やレガシー方式を区別します。現代のGUIDはRFCバリアントとして生成されるため、多くのドキュメントで2つの用語は互換に使われます。
v1のタイムスタンプが1582年から始まるのはなぜですか?
60ビットのカウンターは、1582年10月15日のグレゴリオ暦改暦から100ナノ秒間隔で刻みます。カウンターが十分過去に始まるよう選ばれた結果、あと何千年もオーバーフローしません。代償は読めることのなさです。変換器なしでは、v1のタイムスタンプは意味を成しません。v7のUnixミリ秒が選ばれた理由のひとつは、日付としてそのまま読めることにあります。