uuid ulid nanoid database distributed-systems backend

現代的なユニーク識別子 (ID) 選択ガイド:UUID v4 を超えて

UUID v1-v8、ULID、NanoID、CUID2、Snowflake ID を徹底解説。データベース、分散システム、URL の安全性に最適な識別子の選び方を学びます。

適切なユニーク識別子 (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 スキームを決定してください。将来の自分(そしてデータベース)が、その決定に感謝することでしょう。