UUIDバージョンの説明 — v4をすべての場面で使用しないでください
UUID v4 はどこでもデフォルトですが、データベースインデックスを分割します。v4、v7、ULID をそれぞれいつ使うべきか、そしてDBAが感謝するようになる理由を紹介します。
あなたのコードベースのどこかに、このような行があるでしょう: id = uuid.v4(). それはうまく動きます。テストは通ります。ユーザーはまったく不満を言いません。しかし、DBAはクエリプランを見たときに静かに不満を抱えています。
UUID v4がデフォルトになったのは、シンプルで、どこでも利用可能であり、衝突が実際に起きるほど耐性があるからです。しかし、「うまく動く」と「正しいツール」とは同じではありません——データベースの主キーとしてv4を使うと、システムが拡大するにつれて、実際にシステムの速度が遅くなるのです。
UUID v4がデータベースに与える実際の影響
関係データベースは、主キーのためにB-treeインデックスを使用します。B-treeはデータを並べて配置し、データベースがO(log n)時間で行を検索できるようにします。新しい行を挿入するとき、データベースはインデックスの正しい並び順の位置にそれを配置しなければなりません。
UUID v4では、新しいIDはすべてランダムです。 550e8400-e29b-41d4-a716-446655440000 might be followed by f47ac10b-58cc-4372-a567-0e02b2c3d479 — 連続した挿入の間には関係がありません。データベースは毎回、B-treeのランダムな葉ノードに移動しなければなりません。
これは、スケールアップ時に2つの問題を引き起こします:
- ページ分割: B-treeの葉ページが満たされたとき、データベースはそれを2つのページに分割し、親ノードを更新する必要があります。ランダムな挿入では、インデックス全体に頻繁に分割が発生します——末端だけではなく、すべての場所に。
- キャッシュミス: データベースバッファプールは、最近使用されたページをメモリに保持しています。順次挿入は同じ「ホット」ページを繰り返しアクセスします。ランダムな挿入はインデックス全体を散らばって読み取りを分散させ、キャッシュを吹き飛ばし、ディスク読みを強制します。
百万行以上の行と高い書き込み負荷を持つテーブルでは、このインデックスの分割が実際の遅延をもたらします。EXPLAIN ANALYZEがインデックススキャンが予想以上に長くかかると示している場合、ランダムなUUIDが診断の一部である可能性があります。
UUIDの家族樹
UUID v1: タイムスタンプ、MACアドレス、そしてなぜ使わないのか
UUID v1は元々「並べ替え可能な」UUIDでした。1582年10月からの100ナノ秒単位の60ビットのタイムスタンプ、時計シーケンス、そしてあなたのマシンのMACアドレスを組み合わせています。結果として、時間順に並べ替え可能な値になります。
MACアドレスの部分がv1を殺したのです。すべてのIDにあなたのサーバーのネットワークインターフェース識別子が漏れ出します——すべてのユーザー記録、すべての注文、すべてのイベント。セキュリティ研究者が、同じマシンから生成されたv1 UUIDの1つのサンプルをもとに予測可能であることを示しました。組織はユーザー対応の用途でそれを避けるようになり、多くのUUIDライブラリはそれを非推奨としました。
UUID v4: ランダム、安全だが、主キーに不向き
UUID v4は122ビットの暗号的にランダムなデータ(残りのビットはバージョンを表す)です。10億個のUUIDの衝突確率は約10^18分の1です。実用的にはゼロです。
そのランダム性は、セキュリティトークン、セッションID、APIキー、および相関IDなど、予測されず、数えられないIDが必要な用途にちょうどよいです。これらの用途ではv4を続けましょう。問題は、「予測できない」と「データベースに優しい」はまったく逆の性質なのです。
UUID生成を実験したいですか? IO ToolsのUUID生成器 v1、v4、v7、およびその他のバリエーションを同時に生成して、構造の違いを確認できます。
UUID v7: あなたが使うべき新しいデフォルト
UUID v7は2023年5月にIETFがRFC 9562で標準化されました。最も重要な48ビットにミリ秒単位のUnixタイムスタンプを配置し、4ビットのバージョンフィールド、12ビットのシーケンスカウンター、そして62ビットのランダムデータを含んでいます。
実際の意味としては、生成されたUUIDは時系列的に大きくなります。連続した挿入はB-treeの隣接位置に配置されます。ランダムな散らばりがなく、不要なページ分割も、キャッシュの過熱もありません。データベースの視点から、自動増分整数のように振る舞います——同時に、協調なしにグローバルに一意です。
1ミリ秒内に生成されたシーケンスカウンターは、高頻度生成でも単調な順序を保証します。1ミリ秒内に10,000個のUUIDを生成しても、正しい順序になります。ランダムなサフィックスは、分散システム間の衝突を極めて低い確率で保ちます。
PostgreSQL、MySQL、または他の関係データベースを使用する新しいシステムでは、UUID v7を主キーとしてデフォルトにすべきです。
ULID: それ以前に登場した代替案
ULID(Universally Unique Lexicographically Sortable Identifier)は、UUID v7が存在する前から同じ問題を解決していました。ミリ秒単位のUnixタイムスタンプを48ビットに使用し、80ビットのランダムデータをCrockfordのBase32でエンコードしています。
結果として、26文字の文字列が得られ、 01ARZ3NDEKTSV4RRFFQ69G5FAV の36文字のハイフン区切りUUIDフォーマットに比べて、見やすくなります。URLに安全で、文字列として正しい順序に並び、大文字小文字を無視します。
ULIDはIETFのRFCを持っていません——ulid.github.ioにあるコミュニティ仕様があります。ほとんどのチームにはこれで十分ですが、規制環境で正式な標準化が必要な場合は、UUID v7がより安全な選択です。ULIDはJavaScriptやGoエコシステムで強いライブラリサポートを持ち、チームがすでにそれを使っている場合は、急いで切り替えする必要はありません。
並べて比較する
| 財産 | UUID v1 | UUID v4 **UUID**は**バージョン4**のものです。 | Snowflake | ULID |
|---|---|---|---|---|
| はい(整数) | 部分的に | いいえ | はい | はい |
| 衝突耐性 | はい | はい | はい | はい |
| データベースに優しい | 部分的に | いいえ | はい | はい |
| プライバシー安全 | なし(MACアドレス) | はい | はい | はい |
| 標準化組織 | IETF RFC 4122 | IETF RFC 4122 | IETF RFC 9562 | コミュニティ仕様 |
| 典型的な長さ | 36文字 | 36文字 | 36文字 | 26文字 |
| エントロピー源 | MAC + クロック | ランダム | タイムスタンプ + ランダム | タイムスタンプ + ランダム |
それぞれに使うべきタイミング
Snowflake — 新しいシステムのデータベース主キーにこれを使うべきです。IETF標準であり、成長中のライブラリサポート(PostgreSQL 17でネイティブ、主要な言語すべてでライブラリあり)があり、協調なしでB-treeに優しい順序を提供します。
UUID v4 **UUID**は**バージョン4**のものです。 — セキュリティに重要なランダム性が必要な用途(セッショントークン、パスワードリセットトークン、APIキー、OAuthステートパラメータ、ログの相関ID)では、これを使い続けましょう。予測不可能性はここでは特徴であり、欠陥ではありません。
ULID — JavaScriptやGoプロジェクトで既にULIDを使っている場合は、これを使いましょう。短いフォーマットはURLやログで本当に良いです。新しいプロジェクトでは、IETFのバックアップがあるため、UUID v7がより安全な長期的な選択です。
UUID v1 — 使わないでください。v1が新しいコードに適している状況はまったくありません。
移行の考慮事項
既存のシステムでUUID v4の主キーを使用している場合は、すぐに移行する必要はありません——そして、軽率に移行しないでください。外部キー関係、アプリケーションコード、そしてキャッシュされた値がそのIDを参照しています。移行には慎重な計画が必要であり、ほぼ確実にメンテナンスウィンドウが必要です。
ほとんどのチームにとって、現実的なアプローチは:すべての新しいテーブルとサービスにUUID v7(またはULID)を使用することです。古いテーブルにv4が存在していることに受け入れ、パフォーマンスの影響が測定可能な場合は、定期的なインデックス再構築で問題を管理します。完璧を敵にできるわけではありません。
新しいプロジェクト、新しいデータベース、新しいテーブルの場合、v4を主キーとして使う理由はありません。ツールはすでに用意されています。 いくつかのUUID v7のサンプルを生成 そして、何に直面しているかを確認してください。
まとめ
UUID v4は間違っているわけではありません——ただ、頻繁に誤用されています。そのランダム性はセキュリティの性質であり、セキュリティが重要な場所ではそれを保持すべきです。データベース主キーにおいて、そのランダム性はスケールアップ時にパフォーマンスの負担になります。
UUID v7は問題をきれいに解決しています:単調に増加し、グローバルに一意であり、標準化されており、すでにデータベースやORMでサポートされています。今日新しいデータベーススキーマを書いている場合、v7をデフォルトにすべきです。未来のあなた——そしてあなたのDBA——がその違いに気づくでしょう。
恵 スコアボードが到着しました!
スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!
