はじめに
id と UUID に関する技術記事は数多くありますが、私自身は「なんとなく理解しているつもりでも、人に説明しようとすると曖昧になる」という状態でした。そこで、自分の理解を整理・深める目的で本記事をまとめます。
検証環境
- PostgreSQL:15.1
- Windows 11 Pro
- プロセッサ:13th Gen Intel(R) Core(TM) i7-13700 (2.10 GHz)
- RAM:32GB
idについて
PostgreSQL では、id カラムを serial 系型にするとシーケンスによる自動採番が行われます。以下にユーザテーブルの例を示します。
CREATE TABLE public.users (
id bigserial NOT NULL,
"uuid" uuid DEFAULT gen_random_uuid() NOT NULL,
"name" text NOT NULL,
email text NULL,
CONSTRAINT users_pkey PRIMARY KEY (id),
CONSTRAINT users_uuid_key UNIQUE (uuid)
);
id に bigserial 型を指定すると、自動的にシーケンスが作成されます。この例では users_id_seq です。
SELECT sequencename FROM pg_sequences;
| sequencename |
|---|
| users_id_seq |
内部的には以下の処理が自動で行われます1。
-- 1. シーケンスオブジェクトの作成
CREATE SEQUENCE users_id_seq;
-- 2. idをDEFAULT値にシーケンスを設定
ALTER TABLE users ALTER COLUMN id SET DEFAULT nextval('users_id_seq');
-- 3. シーケンスに所有権を設定
ALTER SEQUENCE users_id_seq OWNED BY users.id;
発行済のシーケンスを確認するには以下のコマンドを実行します。
SELECT last_value FROM users_id_seq;
| last_value |
|---|
| 1100000 |
他のシーケンス操作はこちらをご覧ください。
UUIDについて
UUID(Universally Unique Identifier)は 128 ビットの一意な識別子です。歴史的な詳細は省きますが、単一マシンでの処理が前提だった時代から、複数のシステムがネットワーク越しに動作する分散環境へと移行するにつれ、ID の衝突を避ける必要性が高まりました。その解決策として「どのシステムで生成しても重複しない ID」として UUID が考案されました。
例:
550e8400-e29b-41d4-a716-446655440000
idとUUIDの使い分け
下記テーブルにidとUUIDの使い分けを整理しました。
| 観点 | id(自動連番) | UUID | 備考 |
|---|---|---|---|
| 主な用途 | 内部PK・JOIN・内部参照 | 外部公開ID・API・URL | 内部は性能/省メモリ重視、外部は推測耐性と分散一意性が重要 |
| サイズ | 8バイト | 16バイト | UUIDは倍の長さ→インデックス密度が下がり、キャッシュ効率も低下 |
| 衝突の可能性 | 単一DB内ではなし | 事実上ゼロ | |
| 検索・JOIN性能 | 高速 | やや劣る | 比較コストとインデックスのサイズ差がヒット数/キャッシュに影響 |
| 推測可能性 | 容易(列挙攻撃に弱い) | 困難(列挙耐性高い) | |
| 移行・マージ | 衝突しやすい | 衝突しにくい | 別DBの同じ番号がぶつかる。UUIDはグローバル一意性で回避 |
| 実務での使い分け | 内部はid | 外部に公開するものはUUID | 内部は性能優先、外部は推測耐性・分散性優先 |