適切なユニーク識別子 (ID) の選択は、システムアーキテクチャにおいて最も重要な決定の一つです。不適切な ID を選択すると、データベースのパフォーマンスのボトルネック、セキュリティの脆弱性、または分散システムの同期問題につながる可能性があります。長年、UUID v4 は開発者の「デフォルト」の選択肢でした。しかし、分散システムや大規模データベースの進化に伴い、UUID v4 の限界(ソート可能性の欠如や B-Tree インデックスの断片化など)が顕著になってきました。
このガイドでは、UUID の進化を深く掘り下げ、ULID や NanoID などの現代的な代替案を探索し、特定のユースケースに最適な ID を選択するためのフレームワークを提供します。
1. UUID の進化 (RFC 4122 から RFC 9562 へ)
Universally Unique Identifier (UUID) は、数十年にわたって業界標準であり続けています。最近、IETF は RFC 9562 で規格を更新し、現代のデータベースや分散システムのニーズに合わせて設計された新しいバージョンを導入しました。
UUID v1: 時間ベース
UUID v1 は、現在のタイムスタンプ、クロックシーケンス、および生成マシンの MAC アドレスを組み合わせたものです。
- メリット: 空間と時間における一意性が保証される(MAC アドレスが一意である場合)。
- デメリット: プライバシーの懸念(MAC アドレスが露出する)、および異なるマシンで生成された場合に単調増加しないため、B-Tree のパフォーマンスを低下させる可能性があります。
UUID v3 & v5: 名前ベース (MD5/SHA-1)
これらは決定的です。同じ名前空間と名前を指定すれば、常に同じ UUID が得られます。
- UUID v3: MD5 を使用。
- UUID v5: SHA-1 を使用(v3 より推奨)。
- ユースケース: 一意の入力に基づいて再現可能な ID が必要な場合(例:URL から ID を生成するなど)。
UUID v4: ランダム
最も一般的なバージョンで、122 ビットのランダムビットで構成されています。
- メリット: 衝突確率が極めて低く、機密情報が露出しない。
- デメリット: 完全にソート不可能。B-Tree インデックス(MySQL の InnoDB など)の主キーとして使用すると、大規模な「インデックスの断片化」と「ページ分割」を引き起こし、テーブルが大きくなるにつれてパフォーマンスが著しく低下します。
新世代: UUID v6, v7, v8
RFC 9562 では、UUID フォーマットを維持しつつ v4 のソートの問題を解決するために、これらが導入されました。
UUID v7: 新しいゴールドスタンダード
UUID v7 は 時間順に並べ替え可能 (Time-ordered) です。48 ビットの Unix タイムスタンプ(ミリ秒精度)の後にランダムビットが続きます。
- 優れた点: 辞書順にソート可能です。データベースの主キーとして使用すると、新しいレコードが B-Tree の末尾に追加されるため、ページ分割が最小限に抑えられ、高いパフォーマンスが維持されます。
- 推奨: ほとんどすべての新しいプロジェクトにおいて、デフォルトの ID として UUID v7 が UUID v4 に取って代わるべき です。
UUID v6
ソート可能にするために、UUID v1 の順序を入れ替えたものです。UUID v1 の構造にレガシーな依存関係があるが、ソート機能が必要な場合にのみ使用してください。
UUID v8
UUID 構造を維持しながら、カスタム実装を可能にします。128 ビットの ID 内に特定のメタデータを埋め込む必要がある独自システムに有用です。
2. 現代的な代替案の深掘り
UUID は標準ですが、可読性、長さ、または分散生成における利点から、いくつかの代替案が人気を集めています。
ULID (Universally Unique Lexicographically Sortable Identifier)
ULID は UUID v7 の強力な競合相手です。
- 構造: 48 ビットのタイムスタンプ + 80 ビットのランダム性。
- エンコーディング: Crockford の Base32 を使用。長さはわずか 26 文字です(標準の UUID 文字列は 36 文字)。
- メリット: URL セーフ、ケースインセンシティブ(大文字小文字を区別しない)、ソート可能、そして UUID よりも見た目が短い。
- デメリット: 標準の UUID フォーマットではないため、一部の古いデータベースではネイティブの 128 ビット UUID/GUID 型ほど効率的に処理できない場合があります。
NanoID: 小さくて速い代替案
NanoID は、フロントエンドや Web アプリケーションでよく使用されます。
- メリット: UUID より大幅に小さく、使用するアルファベットを高度にカスタマイズ可能で、UUID v4 より高速。
- セキュリティ: 暗号的に強力なランダムジェネレーターを使用。
- ユースケース: 短縮 URL ジェネレーターや、短くて推測しにくい文字列が求められる公開用のレコード ID に最適です。
CUID2: 次世代の安全な ID
CUID2 は、セキュリティと水平スケーラビリティを考慮して設計されています。
- 特徴: 高い衝突耐性、非連続性(列挙攻撃の防止)、および異なるプログラミング言語間でのポータビリティ。
- ユースケース: セキュリティと水平スケーラビリティが、厳密な時間ソートよりも重要な場合。
Snowflake ID: 分散システムの重量級
元々 Twitter によって開発された Snowflake ID は、64 ビット整数です。
- 構造: タイムスタンプ + ワーカー ID + シーケンス番号。
- メリット: 生成が極めて高速で、標準の BIGINT (64ビット) に収まり、時間順に並びます。
- デメリット: クラスター内での衝突を防ぐために、中央集中型または調整された「ワーカー ID」の割り当てが必要です。
3. 比較表
| 特徴 | UUID v4 | UUID v7 | ULID | NanoID | Snowflake | CUID2 |
|---|---|---|---|---|---|---|
| 長さ | 128 ビット | 128 ビット | 128 ビット | 可変 | 64 ビット | 可変 |
| ソート可能 | いいえ | はい (時間) | はい (時間) | いいえ | はい (時間) | いいえ |
| フォーマット | 16進数 | 16進数 | Base32 | 英数字 | 整数 | 英数字 |
| 衝突リスク | 無視可能 | 無視可能 | 極めて低い | 設定可能 | ゼロ (調整時) | 極めて低い |
| 可読性 | 低い | 低い | 良い | 非常に良い | 良い | 良い |
| DB ネイティブ型 | はい | はい | いいえ (Binary/String) | いいえ (String) | はい (BIGINT) | いいえ (String) |
4. ID 選択のベストプラクティス
データベースの主キーとして
- データベースが 128 ビット UUID をサポートしている場合(PostgreSQL、モダンな MySQL、SQL Server)、UUID v7 を使用 してください。一意性と B-Tree パフォーマンスのバランスが最も優れています。
- 大規模な分散システムを構築しており、64 ビット整数でスペースを節約したい場合は、Snowflake ID を使用 してください。
- 巨大なテーブルでの UUID v4 の使用は避けてください。ランダムな挿入によって書き込みパフォーマンスが破壊されます。
公開 URL 用
- NanoID または SQID を使用してください。短く、URL セーフで、見た目も良いです。
- Short UUID(Base58 または Base62 でエンコードされた UUID)も、基盤となる一意性を維持しつつ、クリーンな URL を提供するための優れた選択肢です。
分散システム (マイクロサービス) 用
- ULID または KSUID は、Snowflake とは異なり中央調整役を必要とせず、デバッグやロギングに役立つ時間ベースの順序を提供するため、非常に優れています。
5. コード例
Node.js で UUID v7 を生成する
uuid パッケージを使用:
const { v7: uuidv7 } = require('uuid');
console.log(uuidv7()); // 例: '018c3b7a-6b5d-7e8c-9a1b-2c3d4e5f6g7h'
Python で ULID を生成する
python-ulid ライブラリを使用:
from ulid import ULID
ulid = ULID()
print(ulid) # 例: '01H6P7XG6WJ9S5H8K4M6N7B2P1'
6. よくある落とし穴 (FAQ)
Q: 既存の UUID v4 を UUID v7 に変換できますか? A: いいえ、ビット構造が異なります。ただし、新しいレコードから UUID v7 を使い始めることは可能です。ほとんどのデータベースは、同じ UUID カラムに両方を保存できます。
Q: NanoID は UUID と同じくらい安全ですか? A: はい、長さとアルファベットが適切に選択されていれば安全です。21 文字の NanoID は、UUID v4 と同等の衝突確率を持ちます。
Q: なぜオートインクリメント(連番)整数を使わないのですか?
A: オートインクリメントは、小規模な単一ノードのデータベースには適しています。しかし、競合他社にデータ量(例:user/5000 はユーザーが 5,000 人いることを示唆)を推測されやすく、分散システムでの管理が困難です。
7. まとめ
2026 年において、データベースの主キーに UUID v4 を使い続ける理由はほとんどありません。UUID v7 の登場により、互換性を維持しながらパフォーマンスの問題を解決する、標準化された時間順のソリューションが提供されました。特殊なニーズには、可読性に優れた ULID や、大規模分散アーキテクチャで最大の効率を誇る Snowflake ID が選択肢となります。
ソート可能性、可読性、パフォーマンスのニーズを評価した上で、ID スキームを決定してください。将来の自分(そしてデータベース)が、その決定に感謝することでしょう。