MySQL の PRIMARY KEY と AUTO_INCREMENT

テーブル設計において主キー(PRIMARY KEY)は最も基本的かつ重要な要素です。主キーの選択はテーブルの物理的な格納構造にまで影響し、一度決めると変更が難しいため、設計段階でしっかり検討する必要があります。

PRIMARY KEY の基本

PRIMARY KEY は各行を一意に識別するためのカラムまたはカラムの組み合わせです。MySQL の InnoDB エンジンでは、主キーがクラスタインデックスとして使われ、データの物理的な格納順序が主キーの順番で並びます。

主キーのカラムは自動的に NOT NULL になる
1つのテーブルに主キーは1つだけ
単一カラムでも複合カラムでも指定可能
InnoDB ではクラスタインデックスとして機能する

AUTO_INCREMENT の仕組み

最もよく使われるのが、INT や BIGINT に AUTO_INCREMENT を付けて自動採番する方式です。

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  email VARCHAR(254) NOT NULL UNIQUE
);

-- id は自動で 1, 2, 3... と採番される
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');

AUTO_INCREMENT は連番を保証するわけではなく、トランザクションのロールバックや DELETE によって欠番が生じることがあります。欠番を許容できない業務要件がある場合は、別途採番テーブルを設けるなどの工夫が必要です。

サロゲートキーとナチュラルキー

主キーの設計方針は大きく2つに分かれます。

サロゲートキー

業務的な意味を持たない連番 ID を主キーにする方式。AUTO_INCREMENT の INT/BIGINT が典型例です。主キーの値が変わることがなく、外部キーの管理もシンプルになります。

ナチュラルキー

メールアドレスや社員番号など、業務上意味のある値を主キーにする方式。正規化の観点では理想的ですが、値の変更が発生すると関連テーブルすべてに波及するリスクがあります。

実務ではサロゲートキーを採用するケースが圧倒的に多く、ナチュラルキーは UNIQUE 制約として別途設定するのが一般的です。

UUID を主キーにする場合

分散システムやマイクロサービスでは、UUID を主キーにするケースもあります。ただし、ランダムな UUID(v4)はクラスタインデックスとの相性が悪く、挿入のたびにページ分割が発生してパフォーマンスが低下します。

UUID v4 の問題点

ランダムな値のため、InnoDB のクラスタインデックスで挿入位置が散らばり、ページ分割が頻発します。大量 INSERT のあるテーブルでは深刻なボトルネックになります。

対策:UUID v7 や ULID

時間順にソート可能な UUID v7 や ULID を使えば、クラスタインデックスとの相性問題を緩和できます。MySQL 8.0 の UUID_TO_BIN() で BINARY(16) に変換して格納するのが効率的です。

複合主キーの注意点

2つ以上のカラムを組み合わせた複合主キーは、中間テーブル(多対多リレーションの結合テーブル)でよく使われます。

-- 中間テーブルの複合主キー
CREATE TABLE user_roles (
  user_id INT NOT NULL,
  role_id INT NOT NULL,
  PRIMARY KEY (user_id, role_id),
  FOREIGN KEY (user_id) REFERENCES users(id),
  FOREIGN KEY (role_id) REFERENCES roles(id)
);

複合主キーを使う場合、カラムの順序がインデックスの利用効率に影響します。先頭のカラムで絞り込むクエリが多い場合は、そのカラムを複合主キーの先頭に置くようにしましょう。主キーの設計はテーブル全体の性能を左右するため、最初に慎重に検討することが大切です。