UUID v4とv7の違い - いつどちらを使うべきか実例で解説
最終更新日: 2026年4月19日
「UUIDは v4 を使っておけば安全」と思われがちですが、DBのプライマリキーに使うと書き込み性能が劇的に落ちることがあります。 2024年5月に標準化された UUID v7(RFC 9562)は、v4の衝突耐性と 時系列ソート性を両立する新しい選択肢です。 この記事ではv4とv7の違い、実務での使い分け、ULIDとの比較までを整理します。
UUID v4 (random) hurts B-tree index performance when used as a DB primary key. UUID v7 (RFC 9562, standardized May 2024) prefixes a millisecond timestamp so rows insert in near-sorted order, retaining v4's collision resistance. This guide compares v4, v7, and ULID, shows generation code per language, and gives a decision flow for picking the right version for DB keys, public URLs, session tokens, and distributed event IDs.
図1: UUID v4 と v7 のビット構造
f47ac10b-58cc-4372-a567-0e02b2c3d479018f4d1a-3b2c-7abc-8def-1234567890abv7は先頭48ビットがUnix時刻(ミリ秒)なので、生成順にソートされる
v4とv7の性能差:なぜ重要か
MySQL InnoDB や PostgreSQL などB-treeベースのDBは、プライマリキーが単調増加だと インデックスへの挿入がほぼ末尾追記となり高速です。 完全ランダムなUUID v4をプライマリキーにすると、インデックスの任意の位置に挿入が発生し、 ページ分割(page split)とI/Oが増えます。 大規模テーブルでは書き込みスループットが数倍〜十数倍悪化する報告が 複数のベンチマーク記事で共有されています(Percona, CockroachDBなど)。
UUID v7は先頭48ビットがタイムスタンプなので、ミリ秒単位で見ればソート済みに近い順序で挿入されます。 結果としてページ分割が抑えられ、v4に比べて書き込み性能は明確に改善します。 同時にv4同様の衝突耐性(74ビットのランダム領域)も維持されます。
使い分けの指針
| 用途 | 推奨 | 理由 |
|---|---|---|
| DBのプライマリキー | v7 | 書き込み性能・範囲検索性能 |
| 公開URLのリソースID | v4 | 生成時刻を推測されたくない |
| トレース/リクエストID | v4 または v7 | ログ解析で時系列ソートしたいならv7 |
| セッションID / トークン | UUIDは使わない | 暗号学的乱数(crypto.randomBytes(32)等) |
| 分散システムのイベントID | v7 または ULID | 時系列+衝突耐性 |
注意点として、セッションIDやCSRFトークンにUUIDを使ってはいけません。 UUID v4は暗号学的に強い乱数で生成されるとは限らず(実装依存)、v7は先頭が時刻で推測可能です。 認証系には crypto.randomBytes(32) 相当の専用乱数を使ってください。
生成方法(言語別)
JavaScript / TypeScript
// v4: 標準API
const v4 = crypto.randomUUID();
// v7: Node.js 23.2.0 以降は標準
// 古い環境では uuid パッケージを使用
import { v7 as uuidv7 } from "uuid";
const v7 = uuidv7();
// "018f4d1a-3b2c-7abc-8def-1234567890ab"Python
# v4: 標準
import uuid
print(uuid.uuid4())
# v7: Python 3.14 以降は標準
# 3.13以前は uuid6 / uuid7 パッケージ
# pip install uuid7
from uuid_extensions import uuid7
print(uuid7())PostgreSQL
-- PostgreSQL 18 から gen_random_uuid() に加え uuidv7() が標準関数化予定
-- 17以前は uuid-ossp 拡張や pg_uuidv7 拡張を利用
CREATE EXTENSION IF NOT EXISTS "pg_uuidv7";
CREATE TABLE orders (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
created_at timestamptz NOT NULL DEFAULT now()
);※ PostgreSQL公式ロードマップは流動的です。使用前にお使いのバージョンで最新の関数名をご確認ください。
図2: UUIDバージョンの選び方
crypto.randomBytes(32)ULIDとの比較
ULIDもUUID v7と同じ「時刻プレフィックス + ランダム」構造を持つ識別子です。 主な違いはエンコーディング:
- UUID v7: 128ビット、16進表記(36文字、ハイフン入り)。 標準規格(RFC 9562)、DB・言語の標準サポートが進行中。
- ULID: 128ビット、Crockford's Base32(26文字、ハイフンなし)。 短く、URL-safe、人間が写経しやすい。標準化団体による仕様はないが採用例多数。
既存のUUIDカラムやUUIDフォーマットのエコシステムに乗せたいならv7、 URLや管理画面で短く見せたいならULID、という棲み分けが現実的です。 新規プロジェクトで迷うなら、標準規格である v7 を選んでおくと後々の選択肢が広いです。
衝突確率の実務的な目安
v4のランダム部は122ビット、v7は74ビット。 バースデー問題の近似で「50%衝突するのに何個生成する必要があるか」を計算すると:
- UUID v4: 約 2.71 × 1018 個
- UUID v7(同一ミリ秒内): 約 1.55 × 1011 個
v7は「同一ミリ秒内で」1,500億個という条件なので、単一サーバで普通に使う限り衝突は現実的に起きません。 大規模分散環境で1ms内に億単位のID生成が発生する場合のみ、実装側で 「同一ミリ秒内のカウンタ領域を確保する」などの対策が行われています(RFC 9562 8.1参照)。
デバッグTips
UUIDの先頭を見ればバージョンが判別できます。
f47ac10b-58cc-4372-a567-0e02b2c3d479
^
4 → UUID v4
018f4d1a-3b2c-7abc-8def-1234567890ab
^
7 → UUID v7v7の先頭12桁は16進のUnixミリ秒タイムスタンプです。0x018f4d1a3b2c を10進変換すると生成時刻が得られます。 本サイトのUUID Generatorで v4・v7を即座に生成できるので、動作確認にお使いください。
まとめ
UUID v7は「DBプライマリキーに使えるUUID」として事実上の標準になりつつあります。 v4の完全ランダム性が必要な用途(公開URL、推測回避)以外では、v7を選ぶのが合理的です。 ただし認証系には絶対に使わず、専用の暗号学的乱数を使うこと。 ここさえ押さえておけば、IDの選択で大きく外すことはありません。
English summary
Use UUID v7 as a DB primary key for better B-tree insert locality and range scans while keeping v4-level collision resistance (74 random bits). Use UUID v4 when you must not leak creation time (public resource IDs). Never use any UUID variant for session tokens, CSRF tokens, or password reset links — use a CSPRNG such ascrypto.randomBytes(32). v7 is now standardized (RFC 9562) with growing native support in Node.js 23.2+, Python 3.14+, and PostgreSQL 18 (planned). ULID shares v7's structure but uses Base32 encoding; pick ULID for short, URL-friendly IDs, v7 for ecosystem compatibility.