UUID v7ジェネレーター

Generate time-ordered UUID v7 for database primary keys

フォーマット

件数:

UUID v7 とは何ですか?

UUID v7 は RFC 9562(2024 年 5 月)で標準化された次世代 UUID フォーマットです。最上位ビットに 48 ビットの Unix ミリ秒タイムスタンプをエンコードし、続いてバージョンとバリアントマーカーが来て、残りのビットは暗号学的に安全なランダムデータで埋めます。

タイムスタンプが上位ビットを占めるため、UUID v7 の値は時系列で並べ替えられます——辞書順でも数値順でも。これにより、ランダムな UUID(v4)が B ツリーインデックスの断片化を引き起こすデータベースの主キーとして非常に適しています。

ランダム UUID がデータベースインデックスを断片化させる理由

B ツリーインデックス——PostgreSQL、MySQL、SQLite およびほとんどの他のデータベースで使用——はキー値でソートして行を保持します。新しい行を挿入すると、データベースはインデックス内の正しいソート位置に配置する必要があります。

UUID v4(完全にランダム)では、各新規挿入はインデックスツリーの本質的にランダムな位置に落ちます。これにより、データベースは内部インデックスページを常に読み取りおよび書き直しを強いられ、満杯のページを分割し、他のページを半空にします。結果として断片化した肥大化したインデックスが生まれ、テーブルが成長するにつれて書き込みと読み取りの両方が遅くなります。

UUID v7 のビットレイアウト

UUID v7 は 128 ビット幅で、6 つのフィールドに分割されます:

ビットフィールド目的
48unix_ts_ms48 ビット Unix タイムスタンプ(ミリ秒)——上位半分全体を占める
4verバージョン番号——常に 0111(10 進数 7)
12rand_a12 ビットの暗号学的に安全なランダムデータ
2varバリアントマーカー——常に 10(RFC 4122 バリアント)
62rand_b62 ビットの暗号学的に安全なランダムデータ

タイムスタンプ精度は 1 ミリ秒です。同一ミリ秒内では、UUID v7 の値はランダムサフィックスで順序付けられます——サブミリ秒での単調増加は保証されませんが、k-sortable(k ソート可能)です:時間的に近くに生成された ID はインデックスでも近くに並びます。

UUID v7 vs UUID v1

UUID v1 と UUID v7 はどちらもタイムスタンプを埋め込みますが、設計において大きく異なります:

機能UUID v7UUID v1
エポック / 時間ベースUnix エポック(1970 年 1 月 1 日)グレゴリオ暦エポック(1582 年 10 月 15 日)
時間精度1 ミリ秒100 ナノ秒
ソート可能はい——設計上 k ソート可能いいえ——タイムスタンプフィールドが UUID レイアウトでスクランブルされている
プライバシーホスト情報の漏洩なし生成ホストの MAC アドレスを埋め込む
DB インデックスパフォーマンス優秀——順次挿入、最小断片化劣る——タイムスタンプがあるにもかかわらず非順次
標準RFC 9562(2024 年)RFC 4122(2005 年)
ネイティブブラウザサポート未対応(crypto.randomUUID v7 なし)ネイティブでは利用不可

時間順 UUID が必要な新プロジェクトには、UUID v1 より UUID v7 を優先してください。UUID v1 はレガシーであり、ホスト情報を漏洩します。

UUID v7 vs ULID

ULID(Universally Unique Lexicographically Sortable Identifier)は UUID v7 と同様の問題を解決します。比較を示します:

UUID v7
  • RFC 9562 UUID 標準に準拠——すべての UUID ツールと互換性あり
  • ハイフン付き 16 進数フォーマット——普遍的に認識される
  • ネイティブデータベース UUID カラムサポート
  • 合計 128 ビット
ULID
  • Crockford Base32 エンコーディング——26 文字、やや コンパクト
  • 大文字小文字を区別せず、あいまいな文字(I、L、O、U)を避ける
  • 一目で人間に読みやすい
  • ライブラリが必要——ネイティブプラットフォームサポートなし

すでに UUID エコシステム(PostgreSQL uuid カラム、UUID を返す REST API)にいる場合は UUID v7 を使用してください。ゼロから始めてより人間にやさしいエンコーディングを好む場合は、ULID が合理的な代替手段です。

データベースでの UUID v7 の使用

UUID v7 はほとんどのデータベースでまだネイティブに生成されませんが、標準 UUID カラムに保存でき、アプリケーションコードまたは拡張機能を通じて生成できます:

PostgreSQL
PostgreSQL:uuid カラムに保存します。pg-uuidv7 拡張は、DB 生成の ID が必要な場合に uuid_generate_v7() サーバーサイド関数を追加します。
MySQL / MariaDB
MySQL / MariaDB:BINARY(16) または CHAR(36) カラムに保存します。アプリケーションコードで生成します。MySQL 8.0+ は UUID_TO_BIN(UUID(), 1) で v1 の順序付き UUID をサポートしますが、v7 はアプリレベルでの生成が必要です。
SQLite
SQLite:TEXT(36 文字)または BLOB(16 バイト)として保存します。アプリケーションコードで生成します。UUID v7 は固定幅のタイムスタンププレフィックスを使用するため、TEXT での辞書順ソートは正しく動作します。

コード例

UUID v7 はまだ crypto.randomUUID() では利用できません。ネイティブサポートが来るまで uuidv7(npm)などのライブラリを使用してください:

JavaScript (browser / Node.js 20+)
function generateUuidV7() {
  const buf = new Uint8Array(16)
  crypto.getRandomValues(buf)

  const ms = BigInt(Date.now())

  // Embed 48-bit Unix ms timestamp
  buf[0] = Number((ms >> 40n) & 0xFFn)
  buf[1] = Number((ms >> 32n) & 0xFFn)
  buf[2] = Number((ms >> 24n) & 0xFFn)
  buf[3] = Number((ms >> 16n) & 0xFFn)
  buf[4] = Number((ms >> 8n)  & 0xFFn)
  buf[5] = Number(ms & 0xFFn)

  // Set version 7 (0111xxxx)
  buf[6] = (buf[6] & 0x0F) | 0x70

  // Set variant (10xxxxxx)
  buf[8] = (buf[8] & 0x3F) | 0x80

  const hex = [...buf].map(b => b.toString(16).padStart(2, '0')).join('')
  return `${hex.slice(0,8)}-${hex.slice(8,12)}-${hex.slice(12,16)}-${hex.slice(16,20)}-${hex.slice(20)}`
}

// Node.js 20+ built-in
// import { randomUUID } from 'node:crypto'  // v4 only — no v7 yet in stdlib
Python (uuid7 library)
# pip install uuid7
import uuid_extensions

uid = uuid_extensions.uuid7()
print(uid)                       # e.g. 018e2b3d-1a2b-7000-8000-abc123456789
print(uid.time)                  # Unix ms timestamp embedded in the UUID

# Or as a plain string
from uuid_extensions import uuid7str
print(uuid7str())
PostgreSQL — generate UUID v7
-- PostgreSQL 13+ extension-free implementation
CREATE OR REPLACE FUNCTION uuid_generate_v7()
RETURNS uuid
LANGUAGE sql
AS $$
  SELECT encode(
    set_bit(
      set_bit(
        overlay(
          uuid_send(gen_random_uuid())
          PLACING substring(int8send(floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint) FROM 3)
          FROM 1 FOR 6
        ),
        52, 1
      ),
      53, 1
    ),
    'hex'
  )::uuid;
$$;

-- Usage as a default primary key
CREATE TABLE events (
  id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
  payload jsonb,
  created_at timestamptz DEFAULT now()
);
TypeScript — extract timestamp from UUID v7
function extractTimestamp(uuid: string): Date {
  const hex = uuid.replace(/-/g, '')
  const ms = parseInt(hex.slice(0, 12), 16)  // first 48 bits = ms timestamp
  return new Date(ms)
}

const uid = '018e2b3d-1a2b-7000-8000-abc123456789'
console.log(extractTimestamp(uid).toISOString())
// → "2024-03-15T10:22:05.259Z"

よくある質問

UUID v7 は UUID v4 と後方互換性がありますか?
はい。UUID v7 は他のすべての UUID バージョンと同じ 128 ビット、32 桁 16 進数、ハイフン付きワイヤーフォーマットを使用します。UUID を保存または転送するシステムは変更なしに UUID v7 を受け入れます。バージョンニブル(7)とバリアントビットにより、UUID 構造を検査するツールに v7 として識別されます。
UUID v7 は生成タイムスタンプを公開しますか?
はい——最初の 48 ビットは Unix ミリ秒タイムスタンプであるため、UUID を持つ人は誰でも大まかな生成時刻(最も近いミリ秒まで)を判断できます。作成時間の公開がユースケースで問題となる場合は、代わりに UUID v4 を使用してください。
UUID v7 を別個の created_at カラムなしにデータベースの主キーとして使用できますか?
はい。UUID v7 はミリ秒精度のタイムスタンプを埋め込んでいるため、その値をデコードして大まかな作成時刻を取得できます。ただし、明確性とインデックス性のために、多くのチームは明示的な created_at カラムを保持し、UUID v7 を ID カラムのみに使用します。
UUID v7 はどれだけのエントロピーを持ちますか?
UUID v7 は 74 ビットのランダムデータ(rand_a の 12 ビット + rand_b の 62 ビット)を持ちます。これは UUID v4 の 122 ビットよりわずかに少ないですが、実際の使用には天文学的に大きな衝突なしの空間を提供します。ランダム性の減少はタイムスタンプのソート可能性を得るためのトレードオフです。
UUID v7 はブラウザまたは Node.js でネイティブにサポートされていますか?
2025 年初頭時点ではまだです。RFC 9562 標準は 2024 年 5 月に発行され、プラットフォームサポートはまだ追いついています。今のところ uuidv7 npm パッケージを使用してください。将来のブラウザおよび Node.js リリースでは crypto.randomUUID({ version: 7 }) または同様の API を通じたネイティブサポートが来るかもしれません。