テーブル命名規約 — プレフィックスで種別を明示する設計
概要
テーブルが数十を超えたあたりから、スキーマは「一覧を眺めただけでは構造がわからない」状態になっていきます。マスタなのかトランザクションなのか、それとも中間テーブルなのか。名前だけでは判別できず、毎回 DDL を開いて確認するという状況は珍しくありません。
この記事では、テーブル名の先頭に「種別を表すプレフィックス」を付ける命名規約を入門者向けに整理します。メリット・デメリット、具体的な設計パターン、そして「どこまでやるべきか」の判断軸までをまとめます。特定の製品や案件に依存しない、一般的な RDBMS を前提にしています。
発生する問題
命名規約が曖昧なまま成長したスキーマでは、次のような症状が出ます。
user,orders,t_history,MstItemのように、単複・種別・記法がバラバラ- 一覧を見ても、どれが実データの中心でどれが補助的なテーブルか分からない
- 中間テーブル(多対多の連結)が普通のテーブルに埋もれて見つけにくい
- ログ・履歴・一時テーブルが業務の主役と同列に並ぶ
- 新規参加者が「このテーブルは触っていいのか」を判断できない
根っこにあるのは、テーブル名がその「役割・種別」の情報を持っていないことです。
なぜ種別が重要なのか
テーブル名は本来「何のデータか(What)」を表しますが、大規模スキーマでは「どういう種類のデータか(Kind)」も同じくらい重要になります。
- マスタ(滅多に変わらない参照データ)
- トランザクション(日々増えていく業務データ)
- 中間テーブル(関連の解決)
- 履歴・監査ログ
- ワーク・一時
これらは寿命・更新頻度・削除ポリシー・バックアップ方針がまったく違うのに、名前上は区別がありません。運用や設計判断で毎回「これは何テーブルだっけ」と確認するコストが積み重なります。
対応: 種別プレフィックス
テーブル名の先頭に短い種別記号を付け、名前だけで種別が分かるようにします。よく使われる体系の一例です。
| プレフィックス | 種別 | 説明 | 例 |
|---|---|---|---|
m_ |
マスタ | 参照系・変化が少ない | m_user, m_product |
t_ |
トランザクション | 業務で増えていくデータ | t_order, t_payment |
r_ |
リレーション(中間) | 多対多の連結 | r_user_role |
h_ |
履歴 | 変更履歴・監査 | h_order |
w_ |
ワーク | 一時・バッチ中間 | w_import_buffer |
v_ |
ビュー | 実テーブルと区別 | v_active_user |
一覧をソートすると種別ごとに固まって表示され、スキーマの地図が一目で掴めます。
記法の原則もセットで決める
プレフィックスだけでなく、以下も同時に規約化すると効果が跳ね上がります。
- 記法を統一する:
snake_caseに統一(大文字小文字を混ぜない) - 単数か複数かを決める: 「テーブル名は単数」などどちらかに固定
- 区切りは 1 文字: プレフィックスと本体はアンダースコアで区切る
- 略語辞書を持つ:
qty,amt,dtなどの略語は表にして共有
実装例
-- マスタ: 変化が少ない参照データ
CREATE TABLE m_user (
id BIGINT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE TABLE m_role (
id BIGINT PRIMARY KEY,
code VARCHAR(50) NOT NULL UNIQUE,
label VARCHAR(100) NOT NULL
);
-- 中間テーブル: 多対多を解決(r_ = relation)
CREATE TABLE r_user_role (
user_id BIGINT NOT NULL REFERENCES m_user(id),
role_id BIGINT NOT NULL REFERENCES m_role(id),
PRIMARY KEY (user_id, role_id)
);
-- トランザクション: 業務で増えていくデータ
CREATE TABLE t_order (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES m_user(id),
total_amt DECIMAL(12,2) NOT NULL,
ordered_at TIMESTAMP NOT NULL DEFAULT now()
);
-- 履歴: 監査・変更ログ(h_ = history)
CREATE TABLE h_order (
id BIGINT PRIMARY KEY,
order_id BIGINT NOT NULL,
changed_at TIMESTAMP NOT NULL DEFAULT now(),
payload JSONB NOT NULL
);
一覧するとこう並びます。種別ごとに固まっているのが分かります。
h_order m_role m_user r_user_role t_order
CI で規約を守らせる
命名規約はドキュメントに書くだけでは守られません。マイグレーション適用後に検査クエリを回すと定着します。
-- 規約プレフィックスで始まらないテーブルを検出(PostgreSQL) SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND tablename !~ '^(m|t|r|h|w|v)_';
これを CI のステップに入れておくと、規約違反のテーブルが混入した時点で気づけます。
確認方法
- 新しいテーブルを 1 つ追加し、一覧が種別ごとに固まって表示されることを確認する
- 上記の検出クエリを実行し、0 件(規約違反なし)であることを確認する
- 一覧だけを第三者に見せ、名前だけで種別を説明できるか確認する
注意点
- 後付けの一括リネームは高コスト: アプリ側の参照・ORM 設定・ビュー・ストアドまで追随が必要。新規スキーマで最初から決めるのが最も安い
- 分類に迷うテーブルは必ず出る: 迷ったときのデフォルト種別を決めておく
- プレフィックスは「種別」に限定する:
tbl_のように全テーブルへ同じ接頭辞を付けるのは情報量ゼロで無意味 - ハンガリアン記法の失敗を繰り返さない: 後から種別が変わっても名前が追随しない問題は起きうる。設計変更時のリネームコストを受け入れる覚悟が要る
- ORM の命名慣習と衝突しないか確認する: 一部フレームワークは複数形・特定命名を強制する
まとめ
- テーブル名は「何のデータか」だけでなく「どういう種別か」も伝えるべき情報を持つ
- 種別プレフィックス(
m_/t_/r_/h_など)は、一覧しただけでスキーマの地図を読ませてくれる - 記法統一・単複ルール・略語辞書・CI チェックをセットで導入すると定着する
- 後付けは高コスト。新規スキーマの立ち上げ時に決めるのがベスト
名前は最初のドキュメントです。命名規約に少し投資しておくと、半年後の自分と、新しく入ってくるメンバーが確実に助かります。
