データベース 2018-08-06

複数のテーブルに多対1で紐づく時のテーブル設計のアプローチについて

複数テーブルへの多対1リレーション設計、ポリモーフィック関連とSQLアンチパターンの回避パターンを実装面から比較

Read in: en
複数のテーブルに多対1で紐づく時のテーブル設計のアプローチについて

概要

複数のテーブルに対し、多対1でテーブルが関係付くときのテーブル設計のパターンについてまとめる。

データ設計

以下のようなケースのデータ設計を例とする。 

commentsissuespullrequestsのどちらに対しても多対一で関係付くようなケース。

ポリモーフィック関連

commentstarget_tabletarget_idというカラムを追加し、issuespullrequestsのどちらに結びつくか判断させようとするテーブル設計。

SQLアンチパターンではアンチパターンの一つとして取り上げられている。

target_idtarget_tableを見ないとissuespullrequestsのどちらに関連付くかわからないため、外部キー制約が使えない。 したがって、このパターンではテーブル間の整合性保持はアプリケーションのロジックに依存することなる。

LaravelやRailsのORMではポリモーフィック関連がサポートされているので実装が楽なので、このようなパターンを検討する余地はゼロではないが、なるべく避けたいパターンではある。

交差(ピボット、中間)テーブル

issuespullrequestsに交差テーブルを用意して、外部キー制約を使えるようにするパターン。

issuesissues_commentsは1対多、issues_commentscommentsは多対1となる。pullrequestsに関しても同様。

アプリケーションの要件次第ではあるが、1コメントがissuespullrequestsのどちらかだけに関連付くようにという制約を保証できない。

外部キーが使えるため、ポリモーフィック関連よりは整合性を保つことができる。 

共通の親を持つテーブル

issuespullrequestscommentsの共通の親となるテーブルを用意するパターン。 

postsはクラステーブル継承の考え方に基づいて定義するのが良さそう。(要は基底クラスと考える) (参考:単一テーブル継承・クラステーブル継承・具象クラス継承について PofEAA

issuespostsが1対1、postscommentsが1対多で関連付く。pull_requestsも同様。 postscommentsは1対多で関連付く。

1コメントは1postsに関連付くという制約を保証できるが、issuespullrequests のどちらかだけに関連付くという制約を保証できない。

テーブル分割

これはそもそもの前提を疑う話ではあるが、comments を1つのテーブルにまとめておくのではなく、別々のcommentsテーブルをそれぞれ用意してテーブルを分割しておけば良いのではないかというパターンである。

所感

アプリケーション側のロジックに依存することは、ヒューマンエラーの可能性を高めるので、テーブル構造にロジックを依存させる設計方針が基本的には良いパターンではないかと思う。 アプリケーションの要件に加えて、クエリの気持ちを考えて最適なパターンを選択できるようにしたい。

Tags: ポリモーフィック SQLアンチパターン
Share: 𝕏 Post Facebook Hatena
✏️ View source / Discuss on GitHub
☕ サポート

このブログを応援していただける方は、以下からサポートをお願いします。いただいたサポートはブログ運営・技術研鑽に活用します。


関連記事