UUID 生成ツール
UUID を生成します。ランダムな v4 と時刻順の v7 を、一つずつでもまとめても。
122 ビットのランダム。いつ作られたかは何も明かしません。
生成中…
UUID とは何か、なぜ存在するのか
UUID — Universally Unique Identifier、Microsoft の文書では GUID とも呼ばれます — は、なじみ深い 8-4-4-4-12 の区切りで 32 桁の 16 進数として書かれる 128 ビットの値です。その全目的は、別々のシステムが互いに調整せず独立に識別子を作り、それでも結果が衝突しないと確信できるようにすることです。データベースの自動採番列と違うのはそこです: 2 台のサーバー、飛行機の中でオフラインの 2 台のモバイル端末、そしてバックグラウンドジョブが、誰の許可も求めずに同じ瞬間にレコードを作れます。
ここでの一意性は保証ではなく確率的なものです。バージョン 4 は 122 ビットを乱数に委ね、これは何十億もの値を生んでも、繰り返しの確率がディスクが黙ってデータを破損する確率よりはるかに低いほど大きな空間です。実務では一意として扱えます。数学が弱点になることはありません。
バージョン 4 と 7 — 重要な選択
バージョン 4 は端から端までランダムです。いつ作られたか、誰が、どの順で、といった情報を一切運びません。それが最大の強みか中心的な欠点かは、どこに置くかで決まります。
バージョン 7 は 2024 年に RFC 9562 で標準化され、最初の 48 ビットをミリ秒の Unix タイムスタンプに置き換え、残りを乱数で埋めます。時刻が先に来て値が左から右へ読まれるため、v7 識別子を素のテキストとして整列させると、時系列にも整列します。
これは見た目だけの違いではありません。データベースは主キーを整列した B ツリーのインデックスに保ちます。v7 キーを挿入すると新しい行はツリーの右端、前の行の隣に着地します — 書き込むページはメモリに残り、インデックスはきれいに育ちます。v4 キーを挿入すると各書き込みがランダムな位置に着地するので、データベースは毎回別のページに触れ、キャッシュのヒット率が下がり、インデックスが断片化します。大きく忙しいテーブルでは挿入スループットの差が大きく、v7 が主キーにこれほど速く採用されたのはそのためです。
- データベースの主キー、イベントやログの識別子、作成時刻で整列や範囲検索したいものには v7 を選んでください。
- 識別子が信頼できない場所に現れ、何も漏らしてはならないとき — あるレコードが別のより少し前に作られたという事実さえも — には v4 を選んでください。
- 相関 ID・冪等キー・ファイル名など、順序が問題にならないところでは、どちらでも構いません。
引き換えになるのはまさにその漏れです: v7 識別子は、それを見る者に、作成された時刻をミリ秒単位で伝えます。行の ID にはたいてい無害でしばしば有用です。パスワードリセットのトークンや公開の共有リンクには、公開するつもりのなかった情報です — そしてそれらはそもそも UUID であるべきではなく、専用のシークレット生成器からのランダムなトークンであるべきです。
同じミリ秒内での順序
多くの v7 実装を捕らえる微妙な点: 現代のハードウェアは 1 ミリ秒に 1 つよりはるかに多くの識別子を生みます。2 つの値がタイムスタンプを共有すると、その順序は続く乱数ビットが決めます — つまりランダムに、です。密なループで 50 個生むと、おおまかにしか整列していない 50 個の値が得られ、v7 を選んだまさにその性質を失います。
RFC 9562 はこれを単調カウンターで扱い、このツールはそれを実装しています: タイムスタンプの直後の 12 ビットがミリ秒内で上へ数えるので、バッチはおおよそではなく厳密に増加します。カウンターが満杯になると — 同じミリ秒に 4096 個を超えると — 生成器は折り返して前より前に整列する値を出す代わりに、次のミリ秒を借ります。NTP 補正で起きる、時計が後ろに動く場合も同じように扱います。
v7 の値を左から右へ読むと、0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b を例に:
- 0190a1b2-c3d4 — 48 ビットのミリ秒 Unix タイムスタンプ。先に来るので、テキスト順が時刻順です。
- 7 — バージョンのニブルで、これを v4 ではなく v7 にするものです。
- e5f — 12 ビットの単調カウンターで、単一のミリ秒内で増えていきます。
- 8 — バリアントビットで、RFC 9562 がすべての現代の UUID に対して固定しています (常に 8、9、a、b のいずれか)。
- a9b-0c1d2e3f4a5b — 残りの 62 ビットで、純粋にランダムです。
UUID の保存と利用
正規の形は小文字でハイフン付きで、RFC 9562 は生成器がまさにそれを出すべきだと言っています — だからこのツールは書式の選択肢を提供しません。実際にはほかの綴りにも出会うでしょう: Microsoft のツールでは大文字で波括弧に包まれ、短い列にしたい誰かがハイフンを取り除いた形もあります。どれも同じ 128 ビットで、比較は大小を無視すべきです。
効いてくるのは保存です。UUID は 16 バイトですが、テキスト形式は 36 文字です — なので文字列として保存すると、行の中で、そしてより重要なのはそれを含むすべてのインデックスの中で、空間が倍以上になります。ネイティブ型があるならそれを使ってください:
uuid -- PostgreSQL: ネイティブの 16 バイト型 BINARY(16) -- MySQL: コンパクト。CHAR(36) は 20 バイト/行を無駄にする uniqueidentifier -- SQL Server crypto.randomUUID() // JavaScript: v4 のみ、セキュアコンテキストが必要 uuid.uuid4() / uuid7() # Python: 標準ライブラリの v4。v7 はライブラリ経由
最後の注意: UUID は識別するもので、認可するものではありません。推測できないため、それを含む未公開の URL を非公開扱いにしたくなります。しかし識別子は漏れます — ログ・ブラウザ履歴・リファラーヘッダー・スクリーンショットを通して — ので、本当に守る必要があるものには、その背後に本物の権限チェックが今も必要です。
よくある質問
- v4 と v7 のどちらを使うべきですか?
- データベースの主キーと、作成時刻で整列したいものには v7 を使ってください: 先頭のタイムスタンプが、挿入をインデックス全体に散らすのではなく末尾にまとめて保ちます。識別子がいつ作られたかも含め何も明かしてはならないときには v4 を使ってください。
- 2 つの UUID が同じになることはありますか?
- 可能ですが、消え入るほど起こりにくいです。バージョン 4 は 122 ビットの乱数を持つので、何十億もの値を生んだ後でも、衝突の確率はストレージが黙ってそれらを破損する確率よりはるかに低いままです。
- バージョン 1、3、5 はどうなったのですか?
- バージョン 1 はタイムスタンプとマシンの MAC アドレスを符号化し、ハードウェアの素性を漏らし、ブラウザではそもそも作れません。バージョン 3 と 5 は、名前空間と名前から MD5 または SHA-1 を使って UUID を決定論的に導きます — 同じ入力が常に同じ識別子を生む必要があるときに有用ですが、新しく生成するのとは別の仕事です。
- UUID はシークレットトークンとして使うほど安全ですか?
- v4 UUID は推測できませんが、v7 は作成時刻を公然と符号化し、どちらも認証情報として意図されていません。パスワードリセット・セッショントークン・共有リンクには、専用のランダムなシークレットを生成し、識別子が推測しにくいことに頼るのではなくサーバー側で権限を確認してください。
- 私の v7 バッチが他のツールで完全に整列していないのはなぜですか?
- 多くの実装が単調カウンターを省くからです。複数の値がミリ秒を共有すると、その順序は続く乱数ビットに委ねられます。このツールは RFC 9562 のカウンターを実装しているので、ここで生成したバッチは厳密に増加します。
- UUID をデータベースにどう保存すべきですか?
- ネイティブの 16 バイト型があるならそれで — PostgreSQL の uuid、SQL Server の uniqueidentifier、MySQL の BINARY(16) です。代わりに 36 文字のテキスト形式で保存すると、行の中と、その列を含むすべてのインデックスの中で、使う空間が倍以上になります。
- これらはあなたのサーバーで生成されるのですか?
- いいえ。プラットフォームの暗号論的乱数源である crypto.getRandomValues を使ってブラウザ内で生成されます — crypto.randomUUID が使うのと同じものです。どの値もどこにも送られず、ページを再読み込みするとまったく新しい一式が得られます。