論理設計アンチパターンレビュー
『SQLアンチパターン Volume 1』第I部(データベース論理設計のアンチパターン)に基づき、 ユーザーが提示したテーブル定義・ER図・スキーマに対してレビューを実施してください。
input の取得(最初に必ず実行)
以下の優先順位でレビュー対象を特定すること。
1. 引数でファイルパスが指定された場合
スキル呼び出し時に引数としてファイルパスが渡された場合(例: /logical-design-antipattern-review ./schema.sql)、そのファイルを Read ツールで読み込む。
2. 引数がなく、会話にスキーマ・DDL・設計情報が貼り付けられている場合
会話中のテキストをそのままレビュー対象として使用する。
3. 引数もなく、会話にも設計情報がない場合
以下を質問してから処理を開始する:
レビュー対象を教えてください。以下のいずれかで指定できます:
- ファイルパス(例: ./schema.sql, ./er-diagram.drawio)
- DDL・テーブル定義を直接貼り付け
ファイル種別ごとの読み取り方針
| 拡張子 | 読み取り方法 |
|---|---|
.sql |
Read ツールでそのまま読み込み、CREATE TABLE / ALTER TABLE 等のDDLを解析する |
.drawio / .xml |
Read ツールでXMLを読み込み、<mxCell> タグのラベル・属性からテーブル名・列名・データ型・制約・リレーションを抽出してER構造を把握する |
.md / .txt |
Read ツールで読み込み、テーブル定義やER図の説明文からスキーマ情報を読み取る |
| その他 | Read ツールで読み込み、内容からスキーマ情報を最大限に読み取る |
drawio ファイルの場合の注意点:
swimlaneスタイルのセルがテーブルを表す- 子セルの
value属性が列名・データ型・制約を示す - エッジ(矢印)がテーブル間のリレーションを示す
- これらを解釈してER構造として理解した上でレビューを行う
レビュー手順
- 上記 input の取得手順に従って対象を特定し読み込む
- 以下の8つのアンチパターンチェックリストに従って順番に確認する
- 該当するアンチパターンを発見した場合は問題点と改善策を日本語で明確に報告する
- 問題がない場合は「問題なし」と明記する
チェックリスト
AP-1: ジェイウォーク(信号無視)
チェック内容: VARCHAR列にカンマ区切りなどで複数値(ID等)を格納していないか
問題点:
- インデックスが使用できずパフォーマンスが悪化する
- 正規表現でのパターンマッチが必要となりクエリが複雑化する
- 集約クエリ(COUNT/SUM/AVG)が困難になる
- バリデーション(参照整合性)が機能しない
- リストの長さに上限が生まれる
確認観点:
VARCHAR列に複数のIDや値をカンマ区切りで格納していないかaccount_id VARCHAR(100)のようにIDを文字列列に格納していないかREGEXPやLIKE '%,%'を使ったクエリが存在しないか
解決策: 多対多の関連には交差テーブル(中間テーブル)を作成する
AP-2: ナイーブツリー(素朴な木)
チェック内容: 階層構造を parent_id のみで表現していないか
問題点:
- 全子孫取得には JOIN をツリーの深さ分だけ繰り返す必要がある
- 深さが可変の場合、クエリを動的に生成しなければならない
- COUNT/SUM などの集約が困難になる
確認観点:
- 同じテーブルの自己参照として
parent_idのみが存在しないか - 深さが無制限の階層データを扱うテーブルで
parent_idだけが頼りになっていないか
解決策: 以下の代替ツリーモデルを検討する
- 再帰CTE(WITH RECURSIVE)
- 経路列挙(Path Enumeration):
/1/2/3/のような文字列でパスを格納 - 入れ子集合(Nested Set): lft/rgt値でツリーを表現
- 閉包テーブル(Closure Table): 全祖先・子孫ペアを格納する別テーブル
AP-3: IDリクワイアド(とりあえずID)
チェック内容: 全テーブルに機械的に id SERIAL PRIMARY KEY を付けていないか
問題点:
- 交差テーブル等で複合キーが必要なのに単一の
id列を使うと重複行を許可してしまう - 自然キー・複合キーが使えるのに冗長な疑似キーが増える
- キーの意味がわかりにくくなる(
idが何を識別しているか不明確)
確認観点:
- 交差テーブル(多対多)に
id列だけが主キーで、UNIQUE(col1, col2)がないか - 本来自然キーが使える列(メールアドレス等)にも
idを追加していないか - テーブル名やコンテキストから
idの意味が読み取れないか
解決策: 状況に応じて適切に調整する
- 交差テーブルは複合主キーを使う
- 自然キーが一意であれば主キーとして使う
- 列名を
bug_id,account_idのように意味のある名前にする
AP-4: キーレスエントリ(外部キー嫌い)
チェック内容: 外部キー制約が宣言されていない関連が存在しないか
問題点:
- アプリケーション側で参照整合性を保証するコードが必要になる
- 「完璧なコード」を前提とした脆弱な設計になる
- 孤立した参照(存在しない親を参照する子行)が生まれうる
- バグの発見が遅れる(データ破損が起きてから気づく)
確認観点:
- テーブル間に論理的な関連があるのに
FOREIGN KEY制約が宣言されていないか ON DELETE CASCADE/ON DELETE SET NULLの適切な設定がされているか
解決策: 外部キー制約を宣言し、参照整合性をDBに委ねる
AP-5: EAV(エンティティ・アトリビュート・バリュー)
チェック内容: 属性名を行として格納する汎用属性テーブル設計を使っていないか
問題点:
- データ型の制約が効かない(数値も日付も全てVARCHARになる)
- NOT NULL制約が機能しない
- 行を再構築するためのPIVOT処理が必要になりクエリが複雑化する
- 外部キー制約で参照整合性が保てない
- 特定エンティティの全属性をSELECTするためにJOINが爆発する
確認観点:
entity_id,attribute_name,valueのような3列構成のテーブルがないか- 属性名を文字列として格納しているテーブルがないか
- 「オープンスキーマ」「スキーマレス」「名前/値ペア」と呼ばれる設計がないか
解決策: サブタイプのモデリングを行う
- シングルテーブル継承: 全サブタイプを1テーブルに(NULLが多くなる)
- 具象テーブル継承: サブタイプごとに独立したテーブル
- クラステーブル継承: 共通属性を基底テーブルに、固有属性を各サブタイプテーブルに
- 半構造化データ: JSON/XMLカラムを使う(最終手段)
AP-6: ポリモーフィック関連
チェック内容: 外部キーが複数の親テーブルのいずれかを参照する「二重目的の外部キー」を使っていないか
問題点:
- SQL の FOREIGN KEY 制約は複数テーブルへの参照を表現できない
issue_type VARCHAR+issue_id BIGINTのような組み合わせは参照整合性が保てない- JOIN するたびに型の分岐処理が必要になる
確認観点:
target_typeやparent_typeのような「どのテーブルを指すか」を示す列がないか- 外部キーが
REFERENCESなしに定義されている関連IDカラムがないか Comments.issue_type IN ('Bug', 'FeatureRequest')のような型識別カラムがないか
解決策:
- 参照を逆向きにする(子側に外部キーを持つのではなく親側に従属テーブルを作る)
- 共通の基底テーブルを作成して全親テーブルがそれを参照する設計にする
AP-7: マルチカラムアトリビュート(複数列属性)
チェック内容: 同じ種類のデータを tag1, tag2, tag3 のように複数列で表現していないか
問題点:
- 特定の値を検索するとき全列を検索しなければならない
- 列数の上限が値の上限になる
- 未使用列にNULLが増える
- 列の追加にはALTER TABLEが必要
確認観点:
- 同じ種類のデータを
_1,_2,_3のような連番サフィックスで複数列定義していないか phone1,phone2,phone3やtag1,tag2,tag3のような列がないか
解決策: 従属テーブルを作成する(1対多の関連として正規化する)
AP-8: メタデータトリブル(メタデータ大増殖)
チェック内容: データ増加対策として年・月・カテゴリ等でテーブルや列を分割していないか
問題点:
- テーブルや列がトリブルのように制御不能に増殖する
- 全データを対象にしたクエリでUNION ALLが必要になる
- データ整合性の管理が困難になる
- メタデータ(テーブル名・列名)にデータが混入する(例:
sales_2023,sales_2024)
確認観点:
- 年・月・カテゴリ等で名前が変わるテーブルが複数存在しないか(例:
log_2023,log_2024) revenue2022,revenue2023のように年が列名に入っていないか- テーブル名や列名がデータとして機能していないか
解決策:
- 水平パーティショニング(DB機能のパーティショニング)を使用する
- 垂直パーティショニング(列の分割)を検討する
- 年・月は列の値として格納し、テーブル名・列名に埋め込まない
出力形式
## 論理設計アンチパターンレビュー結果
### 発見されたアンチパターン
#### AP-X: [アンチパターン名]
- **箇所:** (問題のあるテーブル名・列名)
- **問題点:** (具体的な問題の説明)
- **改善策:** (推奨する設計変更)
### 問題なし
- AP-X: [アンチパターン名] — 該当なし
### 総評
(全体的な評価と優先度の高い改善点のサマリー)