PostgreSQLにおけるUUID

PostgreSQLでのUUID完全ガイド。ネイティブuuid型、gen_random_uuid()、インデックス戦略、ストレージ最適化、拡張機能によるv7生成をコード例付きで解説します。

Usage

詳細な説明

PostgreSQLはUUIDに対するファーストクラスのサポートを備えており、内部的に16バイトで格納する専用の uuid データ型があります。これは可能な限り最も省スペースな表現です。

UUIDカラムの作成:

-- UUID v4 as primary key (PostgreSQL 13+, no extension needed)
CREATE TABLE users (
    id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    email text NOT NULL UNIQUE,
    created_at timestamptz DEFAULT now()
);

-- Insert with auto-generated UUID
INSERT INTO users (email) VALUES ('alice@example.com');

-- Insert with explicit UUID
INSERT INTO users (id, email)
VALUES ('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'bob@example.com');

UUID生成関数:

関数 ソース バージョン
gen_random_uuid() 組み込み(PG 13+) v4
uuid_generate_v4() uuid-ossp拡張 v4
uuid_generate_v1() uuid-ossp拡張 v1
uuid_generate_v1mc() uuid-ossp拡張 v1(ランダムMAC)
カスタム関数 PL/pgSQL v7

PostgreSQLでのUUID v7: PostgreSQLにはまだ組み込みのv7ジェネレーターがありませんが、PL/pgSQLで作成できます:

CREATE OR REPLACE FUNCTION uuid_generate_v7() RETURNS uuid AS $$
DECLARE
    unix_ts_ms bigint;
    uuid_bytes bytea;
BEGIN
    unix_ts_ms = (extract(epoch from clock_timestamp()) * 1000)::bigint;
    uuid_bytes = set_byte(
        set_byte(
            overlay(
                uuid_send(gen_random_uuid())
                placing substring(int8send(unix_ts_ms) from 3)
                from 1 for 6
            ),
            6, (get_byte(uuid_send(gen_random_uuid()), 6) & 15) | 112
        ),
        8, (get_byte(uuid_send(gen_random_uuid()), 8) & 63) | 128
    );
    RETURN encode(uuid_bytes, 'hex')::uuid;
END
$$ LANGUAGE plpgsql VOLATILE;

あるいは、pg_uuidv7 拡張機能がネイティブC実装によるより高いパフォーマンスを提供します。

インデックスパフォーマンス:

-- B-tree index (default for PRIMARY KEY)
-- Works well with UUID v7 (sequential), poorly with UUID v4 (random)
CREATE INDEX idx_users_id ON users (id);

-- BRIN index (Block Range Index) — excellent for UUID v7
-- Much smaller than B-tree, ideal for append-mostly tables
CREATE INDEX idx_events_id ON events USING BRIN (id);

-- Hash index — O(1) lookups, no range scans
-- Smaller than B-tree, good for equality-only queries
CREATE INDEX idx_sessions_id ON sessions USING HASH (id);

ストレージ比較:

カラムサイズ 1000万行のインデックス
uuid 16バイト 約350 MB
bigint 8バイト 約175 MB
text(36) 40バイト 約750 MB

PostgreSQLでの便利なUUID操作:

-- Cast string to UUID
SELECT '550e8400-e29b-41d4-a716-446655440000'::uuid;

-- Extract timestamp from UUID v7 (approximate)
SELECT to_timestamp(
    ('x' || lpad(left(id::text, 8) || substr(id::text, 10, 4), 12, '0'))::bit(48)::bigint / 1000.0
) FROM events;

ユースケース

PostgreSQLのネイティブUUID型は、行レベルセキュリティポリシーとUUIDを使用したテナント間データ分離を共有データベーススキーマで実現するマルチテナントSaaSアプリケーションの基盤です。

試してみる — UUID Generator

フルツールを開く