メインコンテンツへスキップ
Toolsbase Logo

UUID v4 / v7 / NanoID / CUID2 使い分け完全ガイド

Toolsbase編集部
UUIDNanoIDCUID2RFC 9562識別子データベース

識別子の選択がシステム設計に与える影響

分散システムやデータベースで使われる識別子(ID)は、パフォーマンス・ソート順・セキュリティに直結します。単純に「UUIDを使えばいい」という判断が、後からインデックスの断片化やパフォーマンス問題につながることは珍しくありません。

UUID v4、UUID v7、NanoID、CUID2——それぞれに異なる設計思想があります。この記事では各仕様を参照しながら特性を比較し、ユースケースに応じた選択基準を整理します。


UUID の仕様概要(RFC 9562)

UUID(Universally Unique Identifier)の現行仕様は RFC 9562(2024年5月公開)です。以前の RFC 4122 を廃止して改訂されており、UUID v6 / v7 / v8 が新たに定義されました。

UUID は 128 ビット(16バイト)の値で、ハイフン区切りの 16進数テキスト表現(xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx)が広く使われています。4ビットのバージョン番号(M)と、バリアントを示すビット(N)がフォーマットの一部に含まれます。

現在よく使われるバージョンは以下の通りです。

バージョン 生成方式 時系列ソート
v1 タイムスタンプ + MACアドレス 可(不完全)
v4 完全ランダム 不可
v7 Unix Epoch + ランダム

UUID v4 ── ランダム識別子の標準

構造

UUID v4 の 128 ビットのうち 122 ビットがランダムです。残りの 6 ビットはバージョン(0100)とバリアント(10)に使われます。

xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
                ^         ^
            version=4   variant bits

衝突確率

122 ビットのランダム空間は 2^122(約 5.3 × 10^36)通りです。誕生日問題の公式により、50%の確率で衝突が発生するのは約 2.71 × 10^18 個生成した時点です。実用上、意図的な攻撃がない限り衝突はほぼ起きません。

// Node.js 標準の crypto モジュール
const { randomUUID } = require('crypto');
const id = randomUUID();
// => "f47ac10b-58cc-4372-a567-0e02b2c3d479"

// ブラウザ Web Crypto API
const id = crypto.randomUUID();

主な特性

  • 予測不可能性: 暗号学的に安全な乱数生成器(CSPRNG)を使うため、連続するIDから次のIDを推測できない
  • 時系列ソート不可: IDをそのままデータベースのクラスター化インデックスに使うと、ランダムな挿入位置になりB-treeの断片化が起きる
  • 広い普及: ほぼすべての言語・フレームワークでネイティブサポート

向いているユースケース

  • セキュリティが重要でIDの生成順を隠したい場合(URL中に露出するリソースIDなど)
  • 小〜中規模のデータセットで挿入パフォーマンスが許容できる場合
  • 単純さを優先したい場合

UUID v7 ── 時系列ランダム識別子

RFC 9562 で新たに定義された UUID v7 は、時系列ソート可能でありながら適切なランダム性を持つ識別子です。

構造

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           unix_ts_ms                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          unix_ts_ms           |  ver  |       rand_a          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|                        rand_b                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            rand_b                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

上位 48 ビットが Unix ミリ秒タイムスタンプ(unix_ts_ms)です。残りはバージョン・バリアント・ランダムビット(rand_a / rand_b)で構成され、ランダム部分は 74 ビットあります。

// uuidv7 パッケージ(npm)
import { uuidv7 } from 'uuidv7';

const id1 = uuidv7(); // "0191c0f2-87b2-7000-b3c5-8a1e3b2d5678"
const id2 = uuidv7(); // "0191c0f2-87b4-7001-a2f3-7c9d0e1f2a3b"
// id1 < id2 が文字列比較で成立する(時系列順)

UUIDv7 がデータベースにやさしい理由

多くのデータベース(MySQL InnoDB、SQL Server)では、主キーにB-treeクラスター化インデックスが使われています。UUID v4 のようなランダム値を挿入すると、ページの中間への挿入が頻発してページ分割・断片化が起きます。

UUID v7 はタイムスタンプ先頭のため、ほぼ末尾への追記になり断片化が大幅に減ります。PostgreSQL でのベンチマークでは、大規模データセットで UUID v4 比 30〜50% の挿入速度向上が報告されています。

-- PostgreSQL 17 以降(uuid_generate_v7 は拡張不要)
-- uuid-ossp 拡張または pgcrypto が一般的
CREATE TABLE events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- v4
    -- id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), -- v7(拡張必要)
    created_at TIMESTAMPTZ DEFAULT NOW()
);

向いているユースケース

  • 挿入が多い大規模テーブルの主キー
  • 時系列でのソート・ページネーションが必要な場合
  • UUID の標準フォーマット(128 ビット)を維持したい場合

NanoID ── コンパクトでURL安全なID

NanoID(Andrey Sitnik 作)は 2017 年に公開された軽量な識別子ライブラリです。UUID の代替として設計されており、デフォルトで 21 文字の URL 安全な文字列を生成します。

設計思想

NanoID はアルファベット(デフォルト: A-Za-z0-9_- の 64 文字)と長さを自由に指定できます。UUID より短い表現で同等以上のランダム性を実現します。

デフォルト (21 文字, 64文字アルファベット):
ランダムビット数 = 21 × log2(64) = 21 × 6 = 126 ビット

UUID v4 の 122 ビットより若干多く、実用上の衝突確率は同等以下です。

// npm: nanoid
import { nanoid, customAlphabet } from 'nanoid';

const id = nanoid();     // "V1StGXR8_Z5jdHi6B-myT"
const shortId = nanoid(10); // "IRFa-VaY2b"

// カスタムアルファベット(数字のみ)
const numericId = customAlphabet('0123456789', 12);
console.log(numericId()); // "483920571038"

// 大文字英数字のみ(human-readable)
const humanId = customAlphabet('ABCDEFGHJKLMNPQRSTUVWXYZ23456789', 8);
console.log(humanId()); // "A7XK3M2P"

UUID との比較

項目 UUID v4 NanoID (default)
文字数 36(ハイフン含む) 21
ランダムビット 122 126
URL 安全 いいえ(ハイフンは安全だが長い) はい
ソート可能 いいえ いいえ
バイト数(UTF-8) 36 bytes 21 bytes
標準化 RFC 9562 なし

向いているユースケース

  • URLに直接使われるID(短縮URLのスラッグなど)
  • フロントエンドやモバイルアプリで生成するID(軽量性が重要)
  • UUID の長さが UI に不向きな場面

CUID2 ── 衝突耐性と分散対応

CUID2 は Eric Elliot が提唱した CUID の後継で、2022 年に設計を刷新しました。元の CUID はタイムスタンプとカウンタの組み合わせでしたが、CUID2 は SHA-3 ベースのハッシュに変更されています。

設計目標

CUID2 の主な設計目標は以下の通りです:

  1. 分散環境での衝突耐性: 複数サーバー・複数プロセスで同時に生成しても衝突しない
  2. 時系列の情報を含まない: タイムスタンプを先頭に持たないため、生成時刻を推測されない
  3. Fingerprint の組み込み: 環境情報(ホスト名ハッシュなど)をエントロピーに追加
// @paralleldrive/cuid2
import { createId } from '@paralleldrive/cuid2';

const id = createId(); // "clh3x5y9b0000qzrmn3b24bmi"
// 常に小文字英数字。先頭は常に英字

内部構造

[先頭文字(英字)] + [SHA-3ハッシュ(タイムスタンプ + フィンガープリント + ランダム)]

デフォルト長は 24 文字です。カスタマイズも可能:

import { init } from '@paralleldrive/cuid2';

const createCustomId = init({
  length: 32, // 長さを変更
  fingerprint: 'my-app-server-1', // サーバー識別子
});

console.log(createCustomId()); // "c..." (32文字)

向いているユースケース

  • 多数のサーバーが同時にIDを生成するマイクロサービス環境
  • ID の生成時刻を外部に公開したくない場合
  • 小文字英数字のみの制約がある場合(一部のシステムでは大文字を扱えない)

4つの識別子を総合比較

特性 UUID v4 UUID v7 NanoID CUID2
ランダムビット数 122 74 126 ~160+
時系列ソート
URL 安全
標準規格 RFC 9562 RFC 9562 なし なし
文字数(デフォルト) 36 36 21 24
衝突確率(10億生成時) 無視できる 無視できる 無視できる 無視できる
DB 挿入効率(大規模) 低い 高い 低い 低い
予測不可能性 高い 高い 高い 高い
依存ライブラリ 不要 必要 必要 必要

データベース主キー選択の判断基準

状況別推奨

PostgreSQL を使う場合: PostgreSQL は UUID を native 型としてサポートし、UUID v4 でも十分なパフォーマンスを発揮します。ただし挿入が毎秒数千件を超えるテーブルでは UUID v7 の検討価値があります。

-- PostgreSQL での UUID v7(uuid-ossp v2 または pgcrypto 拡張)
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- uuid_generate_v7() は拡張バージョンにより利用可否が異なる
-- 代替: アプリ層で生成して INSERT

MySQL / MariaDB を使う場合: InnoDB のクラスター化インデックス構造上、UUID v4 はランダム挿入の問題が顕著です。UUID v7 か、バイナリ(16)型への格納が有効です。

-- MySQL で UUID をバイナリとして格納(パフォーマンス改善)
CREATE TABLE users (
    id BINARY(16) PRIMARY KEY DEFAULT (UUID_TO_BIN(UUID(), 1)),
    -- 第2引数 1 は swap_flag: タイムスタンプバイトを先頭に移動(UUID v1のみ有効)
    email VARCHAR(255) NOT NULL
);

MongoDB を使う場合: MongoDB は ObjectID(12バイト、タイムスタンプ先頭)をデフォルト ID として使います。UUID に移行する場合は UUID v7 が ObjectID に近い特性を持ちます。

セキュリティ上の注意

UUID v7 の先頭 48 ビットはタイムスタンプです。URLに直接露出する場合、リソースの作成時刻が漏洩します。これが問題になる場合は UUID v4 か NanoID を選択してください。

https://example.com/api/items/0191c0f2-87b2-7000-b3c5-8a1e3b2d5678
                               ^^^^^^^^^^^^^^^^
                         タイムスタンプ(2024年頃と推測可能)

実装例:Next.js でのID生成

// src/lib/id.ts

// サーバーサイド: crypto.randomUUID() (Node.js 組み込み)
// クライアント対応: uuidv7 パッケージ

import { uuidv7 } from 'uuidv7';
import { nanoid } from 'nanoid';

// データベース主キー用(時系列ソート可能)
export function generateRecordId(): string {
  return uuidv7();
}

// URL スラッグ用(短くURL安全)
export function generateSlug(length = 10): string {
  return nanoid(length);
}

// APIキー用(長くランダム)
export function generateApiKey(): string {
  // 32文字の英数字 + 記号で256ビット相当
  const { customAlphabet } = require('nanoid');
  const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  return customAlphabet(alphabet, 32)();
}

UUID 生成ツール

UUID の生成や形式の確認には UUID ジェネレーター を使えます。v4 と v7 の両方に対応しており、バルク生成もできます。


まとめ

選択基準 推奨
大規模テーブルの主キー UUID v7
セキュリティ重視のリソースID UUID v4
URLに使う短いID NanoID
マイクロサービスの分散ID生成 CUID2
標準規格への準拠が必要 UUID v4 または v7(RFC 9562)

識別子の選択に「唯一の正解」はなく、システムの規模・セキュリティ要件・データベースエンジンの組み合わせで決まります。UUID v7 はデータベースパフォーマンスと標準性を両立する選択肢として、新規プロジェクトでの採用が増えています。


参考文献