Erdmates Logo
Erdmates
ブログ一覧へ
UUIDPostgreSQL主キーインデックス

bigint・UUID v4・UUID v7:主キーの選び方(PostgreSQL 18 の uuidv7() 対応)

bigint・UUID v4・UUID v7 の主キーの長所と短所を比べ、PostgreSQL 18 に入った uuidv7() で変わった点と、状況別の選び方を整理します。

2026年10月12日8 分で読めます

主キーひとつがスキーマ全体に広がる

主キー(Primary Key)はテーブルひとつだけの問題ではありません。そのキーを参照するすべての外部キー列が同じ型になり、インデックス・結合・API の URL・ログまでその値を持ち回ります。そのため主キーの型は、後から変えるのが最も難しい設計判断のひとつです。

実務でよく選ばれる候補は次の 3 つです。

  • bigint — データベースが 1、2、3… と順番に振る整数
  • UUID v4 — 128 ビットのうち 122 ビットがランダムな識別子
  • UUID v7 — 先頭に生成時刻(ミリ秒)を持ち、時刻順に並ぶ UUID

2025 年 9 月 25 日に正式リリースされた PostgreSQL 18 に uuidv7() 関数が入り、3 つ目の選択肢を拡張モジュールなしで使えるようになりました。それぞれの長所・短所と選び方を整理します。

bigint:小さく速いが、番号を振るのはデータベース

PostgreSQL では GENERATED ALWAYS AS IDENTITY で宣言します。従来の serial より SQL 標準に沿った書き方です。

CREATE TABLE customers (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  email text NOT NULL UNIQUE
);

長所

  • 8 バイトで UUID(16 バイト)の半分です。主キーのインデックスも、それを参照する外部キーのインデックスも小さくなります。
  • 新しい値は常にインデックスの右端に追加されるため、書き込みが効率的です。
  • 人が読んだり口にしたりしやすい(「注文 1042 番」)。

短所

  • 番号はデータベースが振るので、保存するまで ID がわかりません。オフラインアプリや、複数のサービスがそれぞれレコードを作って後でまとめる構成では不便です。
  • URL にそのまま出すと次の番号を推測しやすく、総件数や増え方も見えてしまいます。
  • 複数のデータベースのデータを統合すると番号が衝突します。

UUID v4:どこでも作れるが、インデックスに散らばる

CREATE TABLE customers (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),  -- PostgreSQL 18 の uuidv4() と同じ関数
  email text NOT NULL UNIQUE
);

長所

  • アプリケーション・クライアント・別のサービスなど、どこでも事前に作れ、事実上衝突しません。
  • 推測できないため、URL に出しても他のレコードを推し量られにくいです。

短所

  • 値がランダムなので、新しい行が B-tree インデックスの任意の位置に入ります。書き込みの多いテーブルではインデックスページの分割が頻繁に起き、最近書いたデータがメモリキャッシュにまとまらないためディスク I/O が増えます。
  • 16 バイトなので bigint よりインデックスが大きくなります。外部キーが多いほど差は広がります。

MySQL(InnoDB)のように、テーブル自体を主キー順に格納する(クラスタ化インデックス)エンジンでは、このランダム挿入の影響がテーブル全体に及びます。

UUID v7:時刻順に並ぶ UUID

UUID v7 は 2024 年 5 月に公開された RFC 9562 で定義された形式です。128 ビットのうち先頭 48 ビットに Unix 時刻(ミリ秒)を入れ、バージョン・バリアントのビットを除く残りをランダム値で埋めます。RFC 9562 は、可能であれば UUIDv1・v6 の代わりに UUIDv7 を使うべき(SHOULD)としています。

たとえば 019535d9-3df7-79fb-b466-fa907fa17f9e では、先頭の 16 進数 12 桁(019535d9-3df7)が生成時刻で、その次の 7 がバージョンです。

先頭が時刻なので、後で作った値ほどおおむね大きくなります。そのため新しい行は bigint と同じようにインデックスの右端に集まり、UUID v4 のランダム挿入の問題は大きく減ります。どこでも作れて、ランダム部分のおかげで推測しにくいという UUID の長所はそのままです。

注意点

  • ID を見るだけで 生成時刻がわかります。 RFC 9562 もセキュリティ上の考慮事項として、タイムスタンプはごく小さな攻撃面になると書いています。登録日時のように知られると困る情報なら、外部に見せる ID を別に用意してください。
  • サイズは v4 と同じ 16 バイトです。

PostgreSQL 18 での使い方

PostgreSQL 18 からは拡張なしですぐに使えます。

CREATE TABLE orders (
  id uuid PRIMARY KEY DEFAULT uuidv7(),
  customer_id uuid NOT NULL REFERENCES customers(id),
  total_amount numeric(12, 2) NOT NULL,
  created_at timestamptz NOT NULL DEFAULT now()
);

-- ID に含まれる生成時刻とバージョンを確認
SELECT id,
       uuid_extract_timestamp(id) AS id_created_at,
       uuid_extract_version(id)   AS version
FROM orders
ORDER BY id DESC
LIMIT 10;

PostgreSQL 18 の UUID 関連の関数は次のとおりです。

関数説明
uuidv7()時刻順の UUID v7 を生成。uuidv7(interval) で記録する時刻をその分ずらせる
uuidv4()gen_random_uuid() と同じランダムな v4 を生成(バージョンを明示した別名)
uuid_extract_timestamp(uuid)v1・v7 から生成時刻を取り出す(他のバージョンは NULL)
uuid_extract_version(uuid)バージョン番号を確認

uuid_extract_timestamp() があるからといって created_at 列を消さないでください。ID はアプリケーションで事前に作ることも、時刻をずらして作ることもできるため、業務で使う作成日時と常に一致するとは限りません。

MySQL の場合

MySQL 8.4 のドキュメントによると、UUID() は バージョン 1 の UUID を生成し、UUID v7 を作る組み込み関数はありません(ネイティブ対応の要望が MySQL のバグトラッカーに登録されています)。現実的な方法は 2 つです。

  • アプリケーションで UUID v7 を生成し、BINARY(16) 列に保存する
  • UUID() を使うなら UUID_TO_BIN(UUID(), 1) で保存する — 第 2 引数の 1 は時刻部分の並びを入れ替え、値が連番に近い順で入るようにします

どちらの場合も、文字列(CHAR(36))で保存すると 2 倍以上の大きさになるため、バイナリで保存するのがよいでしょう。

状況別の選び方

状況おすすめ
データベースはひとつ、ID を外部に見せないbigint identity
クライアントや複数のサービスが ID を事前に作る必要がある、データを統合するUUID v7
URL・API に ID が出るが、生成時刻が知られても問題ないUUID v7
生成時刻まで隠すべき値(招待リンク、パスワード再設定トークンなど)UUID v4 または別のランダムトークン

すでに UUID v4 で運用しているなら、新しいテーブルから v7 を使うだけで十分なことが多いです。既存のキーを変えると参照しているすべての外部キーも変える必要があるため、効果とコストを先に比べてください。

ERD を描くときに確認すること

  • 外部キーの型は参照先の主キーと同じにします。 uuid と text、bigint と integer が混ざると、結合のたびに型変換が起きたり、制約を作れなかったりします。
  • 主キーの方針はテーブルごとに決めるより、スキーマ全体でひとつのルールにするほうがミスが減ります。例外(外部公開用のトークンなど)は別の列に分けてください。
  • 主キーのインデックスに加え、よく検索する外部キーにもインデックスを付けてください。キーが 16 バイトなら、インデックスのサイズも考慮が必要です。

先にキーの型を決めてからリレーションを描くと、外部キー列の型の不一致を早めに見つけられます。詳しくは外部キーとテーブルのリレーションシップを完全理解とデータベースインデックス完全ガイドで解説しています。

Erdmatesで今すぐ始めましょう

AI搭載ERDエディタでデータベース設計を始めましょう。無料でご利用いただけます。

無料デモを試す無料で始める

関連記事

AIエージェントが読むデータベース:MCP時代のスキーマ設計原則

AIエージェントがMCPを通じてデータベースに直接接続するケースが増えています。エージェントがスキーマを誤って解釈しないように名前・コメント・制約を設計し、権限を安全に分ける方法を整理します。

PostgreSQL 19プレビュー:スキーマ設計と運用に影響する変更点(ベータ4時点)

正式リリースを控えたPostgreSQL 19の変更点のうち、テーブル設計・マイグレーション・運用に直接影響するものを公式リリースノート(ベータ4)に基づいて整理します。ベータで取り下げられた機能や、アップグレード前に確認すべき動作の変更もあわせて見ていきます。

pgvectorでRAG用のベクトルテーブルを設計する:次元、インデックス、フィルタリングまで

PostgreSQLでpgvectorを使って文書の埋め込み(エンベディング)を保存する際のテーブル構造、ベクトル型ごとの次元制限、HNSWインデックス、メタデータフィルタリングの設計を、pgvector 0.8を基準に整理します。

Erdmates Logo
Erdmates

自然言語でデータベースを設計し、AI駆動ERDエディターでチームとリアルタイムでコラボレーション。

サービス

  • 機能紹介
  • 料金プラン
  • デモ
  • SQL→ERD変換

リソース

  • ブログ
  • ヘルプ
  • お問い合わせ

法的事項

  • 利用規約
  • プライバシーポリシー
  • 第三者提供
会社名: Produx|代表者: 최정회
住所: 강원특별자치도 원주시 솔우물2길 4-1 (무실동)
メール: master@erdmates.com
個人情報管理責任者: 최정회|ホスティングサービス提供者: Amazon Web Services

© 2026 Produx. All rights reserved.