リレーショナル DB

テーブル(表)とリレーション(関係)でデータを表現する。スキーマ + SQL + トランザクションの三位一体で、 50 年以上現役の枯れた技術。

基本概念

テーブル例

+-----+-----------------+--------+
| id  | email           | age    |
+-----+-----------------+--------+
| 1   | alice@ex.com    | 30     |
| 2   | bob@ex.com      | 25     |
| 3   | carol@ex.com    | NULL   |
+-----+-----------------+--------+
      

主要 RDB の比較

PostgreSQLMySQLSQLiteSQL Server
用途万能・現代の第一候補Web 全般 / WordPress1 ファイル / 組み込み企業 / Microsoft 環境
JSON強い (jsonb)普通普通普通
拡張圧倒的(pgvector / postgis)少ない少ない商用
ライセンスBSD(自由)GPL / 商用Public Domain商用
トランザクション強いInnoDB で OKOK強い

主要なデータ型

カテゴリ用途
整数SMALLINT / INT / BIGINTID、カウント
シリアルSERIAL / BIGSERIAL(Postgres)自動採番
小数NUMERIC(p,s) / DECIMAL金額(精度厳密)
浮動小数REAL / DOUBLE PRECISION科学計算(誤差あり)
文字列TEXT / VARCHAR(n) / CHAR(n)文字列。Postgres は TEXT 推奨
真偽BOOLEANtrue / false
日時DATE / TIME / TIMESTAMP / TIMESTAMPTZTIMESTAMPTZ 推奨(タイムゾーン付き)
UUIDUUID分散システムで衝突しない ID
JSONJSON / JSONB柔軟データ。JSONB 推奨
配列TEXT[] / INTEGER[]Postgres のみ
バイナリBYTEA / BLOB画像・バイナリ(普通は別ストレージ)

主キー

主キーの選び方

選択長所短所
BIGSERIAL(連番)軽量、ソート可連番が露出 / 分散しにくい
UUID v4分散で衝突しない、URL で出ても安全16B、ランダム → インデックス局所性悪い
UUID v7(時系列含む)UUID 互換 + 順序保持新しいので対応が必要
ULID / NanoID短く時系列も含む標準ではない
業務キー(メール等)意味がある変更されると地獄

外部キー

他のテーブルの主キーを参照することで「このユーザの投稿」のような関係を表現する。

CREATE TABLE users (
  id BIGSERIAL PRIMARY KEY,
  email TEXT NOT NULL UNIQUE
);

CREATE TABLE posts (
  id BIGSERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE
);

ON DELETE / ON UPDATE

制約

CREATE TABLE products (
  id BIGSERIAL PRIMARY KEY,
  sku TEXT NOT NULL UNIQUE,
  name TEXT NOT NULL,
  price NUMERIC(10, 2) NOT NULL CHECK (price >= 0),
  stock INT NOT NULL DEFAULT 0 CHECK (stock >= 0),
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

NULL のとっつきにくさ

リレーションのパターン

1 対 1

ユーザとプロフィール。プロフィール側に user_id UNIQUE を付ける。

1 対 多

ユーザと投稿。投稿側に user_id を持たせる。最も多い形。

多 対 多

投稿とタグ。中間テーブルを作る:

CREATE TABLE post_tags (
  post_id BIGINT NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
  tag_id  BIGINT NOT NULL REFERENCES tags(id)  ON DELETE CASCADE,
  PRIMARY KEY (post_id, tag_id)
);

SQL の基本コマンド分類

分類
DDL(定義)CREATE / ALTER / DROP
DML(操作)SELECT / INSERT / UPDATE / DELETE
DCL(権限)GRANT / REVOKE
TCL(トランザクション)BEGIN / COMMIT / ROLLBACK

詳細は SQL セクション へ。

RDB の強み

RDB の弱み(と対処)

典型的な接続コード

import postgres from "postgres"
const sql = postgres(process.env.DATABASE_URL!)

const users = await sql`SELECT id, email FROM users WHERE age >= ${18}`
//                                              ^ 自動エスケープ

ORM を介すなら Prisma、生 SQL なら postgres / pg / mysql2 / better-sqlite3。

失敗しやすいポイント

症状原因 / 対処
JOIN が遅いFK 列にインデックスなし → インデックス
整合性が壊れるFK / NOT NULL / CHECK で制約を強く
サマータイム / TZ で時刻ズレTIMESTAMPTZ + UTC で保存
NULL の扱いミス= でなく IS NULL、COALESCE でデフォルト
連番 ID が露出UUID v7 / nanoid に変更
主キー無しレプリカ / Realtime で困る、必ず付ける
迷ったら

Postgres を選び、TIMESTAMPTZ で UTC、主キーは UUID v7 か BIGSERIAL、 JSON は JSONB。これで 90% のプロジェクトはスタートできる。