UUIDとは?フォーマット・バージョン・活用事例の完全ガイド
サービスに登録するたびに、アカウントにユニークな識別子が作られます。すべてのAPIリクエストにはトレースIDが付与されます。分散データベースの各行には、他のマシンで生成されたキーと衝突しないプライマリキーが必要です。これらすべての背後にある仕組みが**UUID(Universally Unique Identifier、汎用一意識別子)**です。
本ガイドでは、UUIDとは何か、どのような構造か、各バージョンの内部動作、そしていつ使うべき(あるいは避けるべき)かを解説します。
UUIDの概要
UUIDは128ビット(16バイト)の識別子で、中央管理機関なしにグローバルな一意性を実現するよう設計されています。32個の16進数文字を標準的な8-4-4-4-12形式で表記します。
550e8400-e29b-41d4-a716-446655440000
|------| |--| |--| |--| |----------|
8桁 4 4 4 12桁
32個の16進数文字 + 4つのハイフン = 合計36文字です。ハイフンは可読性のためだけのもので、データは含みません。
基本情報:
- 128ビット = 2^128 ≈ 3.4 x 10^38 通りの値
- RFC 9562(2024年5月、RFC 4122を置き換え)で標準化
- MicrosoftのエコシステムではGUID(Globally Unique Identifier)とも呼ばれる。フォーマットは同一で名称が異なるだけ
- PostgreSQL(
uuid型)、MySQL(BINARY(16)またはCHAR(36))、そしてほぼすべてのプログラミング言語でネイティブサポート
UUIDの内部構造
すべてのUUIDはバージョンに関係なく、固定ビット位置に2つのメタデータフィールドをエンコードしています。
550e8400-e29b-41d4-a716-446655440000
^ ^
| |
バージョン-┘ └-バリアント
バージョンフィールド(ビット48〜51)
13番目の16進数文字(3番目のグループの最初の桁)がUUIDのバージョンを示します。
| 16進数値 | バージョン | 生成方法 |
|---|---|---|
1 | v1 | タイムスタンプ + MACアドレス |
3 | v3 | namespace + nameのMD5ハッシュ |
4 | v4 | 暗号学的に安全な乱数 |
5 | v5 | namespace + nameのSHA-1ハッシュ |
6 | v6 | 並べ替えタイムスタンプ(RFC 9562) |
7 | v7 | Unixタイムスタンプ + 乱数(RFC 9562) |
8 | v8 | カスタム / 実装固有 |
バリアントフィールド(ビット64〜65)
17番目の16進数文字(4番目のグループの最初の桁)がバリアントを示します。RFC 4122/9562のUUIDでは先頭2ビットが 10 であるため、この文字は必ず 8、9、a、b のいずれかになります。
解析の例
550e8400-e29b-41d4-a716-446655440000
↑ ↑
4 → v4 a → RFC 4122バリアント
これはUUID v4(ランダム)、RFC 4122/9562バリアントです。
UUIDバージョン詳解
バージョン1:タイムスタンプ + MACアドレス
UUID v1は最初の設計で、以下をエンコードします。
- 60ビットのタイムスタンプ ― 1582年10月15日(グレゴリオ暦改革)からの100ナノ秒間隔
- 14ビットのクロックシーケンス ― クロック巻き戻り時の重複防止用カウンター
- 48ビットのノード ― 通常はマシンのMACアドレス
| タイムスタンプ | Ver | クロック |Var| ノード(MAC) |
| 60 bits | 4b | 14b |2b | 48 bits |
問題点:
- 生成時刻とハードウェア情報が漏洩する(プライバシーリスク)
- MACアドレスは偽装可能で、一意性が損なわれる
- 1582年のエポックは混乱しやすく、変換が必要
結論: RFC 9562で正式に非推奨。時間ベースのUUIDにはv7を使ってください。
バージョン3:MD5による名前ベース(決定論的)
UUID v3はnamespace UUIDとname文字列をMD5でハッシュします。同じ入力からは常に同じUUIDが生成されます。
import uuid
# namespace = DNS, name = "example.com"
print(uuid.uuid3(uuid.NAMESPACE_DNS, "example.com"))
# → "9073926b-929f-31c2-abc9-fad77ae3e8eb"(常にこの値)
標準で4つのネームスペースが定義されています。
- DNS:
6ba7b810-9dad-11d1-80b4-00c04fd430c8 - URL:
6ba7b811-9dad-11d1-80b4-00c04fd430c8 - OID:
6ba7b812-9dad-11d1-80b4-00c04fd430c8 - X.500:
6ba7b814-9dad-11d1-80b4-00c04fd430c8
結論: 機能的には使えますが、v5を推奨します。SHA-1の方がMD5より強力です。
バージョン4:ランダム ― 最も広く使われるバージョン
UUID v4は122ビットを暗号学的に安全な乱数で埋めます(残り6ビットはバージョンとバリアントフィールド用に予約)。
| ランダム | Ver | ランダム |Var| ランダム |
| 48 bits | 4b | 12 bits |2b | 62 bits |
2^122 ≈ 5.3 x 10^36 通りの値が可能で、衝突確率は天文学的に低くなります。50%の衝突確率に達するには約2.71 x 10^18個のUUIDが必要です。
// すべてのモダンブラウザとNode.jsでサポート
const id = crypto.randomUUID();
console.log(id); // → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
メリット: シンプル、プライバシー保護、あらゆる環境で対応、調整不要。
デメリット: ランダム分布がデータベースのプライマリキーとして使用する際にB-treeインデックスの断片化を引き起こす。データベース中心の用途にはv7を検討してください。
バージョン5:SHA-1による名前ベース(決定論的)
v3と同じ仕組みですが、MD5の代わりにSHA-1を使用します。同じ入力からは常に同じUUIDが生成されます。
import uuid
print(uuid.uuid5(uuid.NAMESPACE_DNS, "example.com"))
# → "cfbff0d1-9375-5685-968c-48ce8b15ae17"(常にこの値)
ユースケース:
- URLやDNS名から安定したIDを生成
- コンテンツアドレッサブルストレージのキー
- 再現可能なテストデータ
重要: v3とv5はセキュリティ用途ではありません。決定論的であるため、namespaceとnameを知っている人なら誰でもUUIDを再現できます。
バージョン7:Unixタイムスタンプ + ランダム(新規プロジェクトに推奨)
UUID v7は最新バージョンで、**RFC 9562(2024年5月)**で導入されました。以下をエンコードします。
- 48ビットのUnixタイムスタンプ(ミリ秒) ― 単調増加
- 74ビットの暗号学的乱数
| Unixタイムスタンプ(ms) | Ver | rand_a |Var| rand_b |
| 48 bits | 4b | 12 bits |2b | 62 bits |
つまりv7のUUIDは生成時刻順に自然にソートされ、新しいUUIDは辞書順で常に古いものより大きくなります。この特性により、B-treeインデックスがランダムに断片化するのではなくシーケンシャルに保たれるため、データベースのプライマリキーに最適です。
import { v7 as uuidv7 } from "uuid";
const id1 = uuidv7(); // T1で生成
const id2 = uuidv7(); // T2で生成(T2 > T1)
console.log(id1 < id2); // → true(辞書順比較)
データベースへの影響: v7のシーケンシャル特性により、v4と比較してインデックスのページスプリットが最大90%削減され、挿入の高速化、インデックスの縮小、キャッシュ性能の向上が実現します。
UUID vs GUID ― 違いは何か?
機能的な違いはありません。GUID(Globally Unique Identifier)はMicrosoftにおけるUUIDの呼称で、Windows、.NET、COM、SQL Serverで使われています。フォーマットは同一で128ビット、8-4-4-4-12の16進数です。
唯一の外見上の違いは、MicrosoftのツールがGUIDを大文字+波括弧で表示する場合があることです。
UUID: 550e8400-e29b-41d4-a716-446655440000
GUID: {550E8400-E29B-41D4-A716-446655440000}
「UUIDとGUIDの違い」を聞かれたら、答えはブランディングの違いです。
特殊なUUID値
RFC 9562では2つの特殊なUUIDが定義されています。
| 名称 | 値 | 用途 |
|---|---|---|
| Nil UUID | 00000000-0000-0000-0000-000000000000 | 値の不在を表す(null に相当) |
| Max UUID | ffffffff-ffff-ffff-ffff-ffffffffffff | 境界マーカーまたはセンチネル値 |
これらを実際の識別子として使用しないでください。定義上ユニークではありません。
衝突確率:誕生日問題
「誕生日問題」は、衝突が起こりうるまでに何個のUUIDが必要かを計算します。UUID v4(122ビットのランダム性)の場合:
| 生成したUUID数 | 衝突確率 |
|---|---|
| 100万 | 約10^-22(事実上不可能) |
| 10億 | 約10^-16(依然として無視できるレベル) |
| 2.71 x 10^18 | 50%(「誕生日の限界」) |
わかりやすく言えば、毎秒10億個のUUIDを生成し続けたとしても、50%の衝突確率に達するまでに86年かかります。実際には、ハードウェア障害、ソフトウェアバグ、宇宙線の方がUUID v4の数学的衝突よりもはるかに高い確率で重複を引き起こします。
計算式:p(n) ≈ n^2 / (2 x 2^122)
UUIDのバリデーション方法
有効なUUIDは以下の正規表現パターンにマッチします(大文字小文字不問)。
^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
チェック内容:
- 8-4-4-4-12の16進数フォーマット
- バージョン桁が1〜7(15文字目)
- バリアントニブルが8、9、a、bで始まる(20文字目)
function isValidUUID(str) {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str);
}
isValidUUID("550e8400-e29b-41d4-a716-446655440000"); // → true
isValidUUID("not-a-uuid"); // → false
各言語でのUUID生成
JavaScript / TypeScript
// ブラウザ & Node.js ― v4が組み込み
crypto.randomUUID();
// npm uuidパッケージ ― v1、v3、v4、v5、v7に対応
import { v4, v7 } from "uuid";
v4(); // ランダム
v7(); // 時系列順
Python
import uuid
uuid.uuid4() # ランダム
uuid.uuid5(uuid.NAMESPACE_DNS, "example.com") # 決定論的
# uuid.uuid7() はPython 3.14以降で組み込み予定
Go
import "github.com/google/uuid"
uuid.New() // v4 ランダム
uuid.Must(uuid.NewV7()) // v7 時系列順
Java
import java.util.UUID;
UUID.randomUUID(); // v4 ランダム
// UUID v7: com.fasterxml.uuid または JDK 21以降の java.util.UUID を使用
SQL(PostgreSQL)
-- v4(PostgreSQL 13以降)
SELECT gen_random_uuid();
-- v7(PostgreSQL 18以降)
SELECT uuidv7();
よくあるユースケース
データベースのプライマリキー
UUIDを使えば、アプリケーション層、クライアント、エッジノードなど、どこでもIDを生成できます。データベースへのラウンドトリップが不要になるため、オフラインファーストアーキテクチャが可能になり、分散システムが簡素化されます。インデックス性能を重視するならv7、順序を気にしないならv4を選びましょう。
APIリクエストトレーシング
エントリーポイント(ゲートウェイ、ロードバランサー)で各APIリクエストにUUIDを割り当て、X-Request-ID などのヘッダーですべての下流サービスに伝搬します。これにより、マイクロサービス間のログ相関が容易になります。
冪等性キー
APIではリトライされたリクエストがリソースの重複作成を防ぐために、UUIDを冪等性キーとして使用します。クライアントは最初のリクエスト前にUUIDを生成し、リトライ時にも同じUUIDを送信します。
セッション識別子
UUIDは大規模なユーザーベースでのセッション衝突を防ぐのに十分な一意性を提供します。自動インクリメント整数と異なり、列挙ができないため、攻撃者が数値をインクリメントして有効なセッションIDを推測することはできません。
コンテンツアドレッサブルストレージ
UUID v5はコンテンツから決定論的なIDを生成します。同じ入力からは常に同じUUIDが得られるため、重複排除、キャッシュ、再現可能なビルドに適しています。
セキュリティ上の注意点
UUIDはセキュリティトークンではない
UUIDは一意性のために設計されたもので、秘匿性のためではありません。主な問題点:
- UUID v1 は生成タイムスタンプとMACアドレスを漏洩する
- UUID v4 は122ビットの乱数を持つが、構造が予測可能(バージョン/バリアントビットが固定)
- UUID v3/v5 は決定論的で、namespaceとnameを知っていれば誰でもUUIDを再現できる
セキュリティトークン、APIキー、セッションシークレットには、128ビット以上の純粋な乱数を生成する専用のCSPRNGを使用してください。
// セキュリティトークン ― UUIDではなく完全にランダム
const token = Array.from(crypto.getRandomValues(new Uint8Array(32)))
.map(b => b.toString(16).padStart(2, "0"))
.join("");
UUID v7は作成時刻を公開する
UUID v7の最初の48ビットにはミリ秒単位の作成タイムスタンプがエンコードされています。v7 UUIDを受け取った人は誰でも作成時刻を抽出できます。
const hex = "01906b5e-4a3e-7234-8f56-b8c12d4e5678".replace(/-/g, "").slice(0, 12);
new Date(parseInt(hex, 16));
// → 2024-07-01T12:34:56.000Z
作成時刻が機密情報である場合はv4を使用してください。
UUIDだけで列挙を防ごうとしない
UUIDは連番整数よりも推測しにくいですが、唯一のアクセス制御メカニズムにすべきではありません。必ず認可チェックを実施し、URLの推測困難性に頼らないでください。
よくある質問
UUIDにハイフンがあるのはなぜ?
8-4-4-4-12形式のハイフンは純粋に人間の可読性のためです。データは含まず、パース時に無視されます。ハイフンなし(32個の16進数文字)で格納するシステムもあり、同様に有効です。
2つのUUIDが同じになることはある?
理論上はあり得ますが、現実的にはありません。122ビットのランダム性を持つUUID v4では、任意のペアが同一になる確率は約5.3 x 10^36分の1です。実際の生成レートでは、宝くじに当選しながら雷に打たれる確率の方がUUIDの衝突に遭遇する確率より高いでしょう。
UUIDは順番になっている?
一部のバージョンのみです。UUID v1、v6、v7はタイムスタンプを含み、時系列でソートされます。UUID v4は完全にランダムで順序はありません。UUID v3とv5は決定論的ですが順序付けされていません。
UUIDのストレージサイズは?
- バイナリ:16バイト(128ビット) ― 最も効率的な格納方法
- 文字列(ハイフン付き):36バイト(ASCII)
- 文字列(ハイフンなし):32バイト(ASCII)
ほとんどのデータベースは内部的にバイナリ形式でUUIDを格納します。PostgreSQLのネイティブ uuid 型はちょうど16バイトです。
プライマリキーにはUUIDと自動インクリメントのどちらを使うべき?
単一データベースのアプリケーションでは自動インクリメントの方がシンプルです(コンパクト、高速、シーケンシャル)。分散システムではUUIDの方が優れています(どこでも生成可能、調整不要、マージセーフ)。UUIDを使う場合は、データベース性能を最大化するためにv7を推奨します。
RFC 9562とは?
RFC 9562は2024年5月に公開された最新のUUID標準です。RFC 4122を置き換え、UUIDバージョン6、7、8を正式に導入しています。v1を非推奨としてv6/v7を推奨し、Nil UUIDとMax UUIDを定義しています。UUID生成やバリデーションを実装する場合、RFC 9562が権威ある参考文献です。
UUIDは異なるプログラミング言語間で使える?
はい。UUIDのフォーマット(128ビット、8-4-4-4-12の16進数)は言語に依存しません。JavaScriptで生成されたUUIDはPython、Go、Java、またはUUIDをサポートする他のあらゆる言語で正しくパースできます。この相互運用性はUUIDの最大の強みの一つです。
UUIDの生成、デコード、バリデーションをすぐに試せます。UUID生成ツールをご利用ください。v1、v4、v5、v7のバッチ生成に対応し、100%ブラウザ上で動作します。