ALLSPICE

スパイスファクトリー株式会社のメンバーが運営するWeb開発メディア

複数のテーブルに対して多対一で紐づくテーブルの設計アプローチ

Posted by 三澤悠人 | |システム開発
複数のテーブルに対して多対一で紐づくテーブルの設計アプローチ

今回は、あまり見かけないようで意外と必要になる「複数のテーブルに対して多対一で紐づくテーブル」の設計について、4つのアプローチをご紹介します。

どのようなケース?

あるテーブルが複数のテーブルのいずれかに対して、自身が多、紐付き先が一で関連する場合のテーブル設計です。
例えば、「記事」と「画像」を投稿できるようなSNSを想定します。
この時、閲覧者が投稿された「記事」と「画像」のどちらにも「コメント」をつけることができる機能があったとします。

複数のテーブルに対して多対一で紐づくテーブル

このような場合に、どのようなテーブルの設計方法があるのか、以下から説明していきます。

1.ポリモーフィック関連

SQLアンチパターンにも登場するこの設計方法。「どのテーブルのどのレコード(id)に紐づくのか」という情報をテーブルに持たせてしまうという方法です。具体的には以下のような設計になります。

ポリモーフィック関連設計

comments.target_tableに関連する対象のテーブル名を、comments.target_idに関連する対象レコードのIDを格納します。
例えば、以下のようなレコードが入ります。

ポリモーフィック関連データ

シンプルな設計方法ですが、SQLアンチパターンでも取り上げられている通り、あまり良い設計ではないと言えます。
具体的には、外部キーの設定ができないため、commentsが紐づく対象について保証することができないというデメリットがあります。
そのため、整合性の保持が完全にアプリケーション側に依存する事になってしまいます。
また、target_idが示す先のテーブルがレコードによって変化してしまうというのは、気持ち悪く感じてしまう人もいるのではないでしょうか?

しかしながら、Ruby On RailsのActiveRecordなどの一部のORマッパーはこのポリモーフィック関連をサポートしているため、そのようなORマッパーを使用する際にはこの方法を使用することをお勧めします。

2.複数の関連テーブル

紐づく対象のテーブルごとに関連テーブルを作成する方法です。以下のような設計になります。

複数の関連テーブル設計

個人的にはあまり無理のない分かりやすい設計ではないかと思います。
1つのコメントが記事と画像の両方に対して紐付かないよう制約をかける事ができない、というデメリットはあります。しかし、対応しているORマッパーを使用しなかった場合の「1.ポリモーフィック関連」の方法と比較すると、データの整合性の担保という観点ではこちらの方法のほうが良い設計になります。
この設計の場合は以下のようなレコードが入ります。

複数の関連テーブルデータ

3.親テーブルの作成

親テーブル(基底クラス)が抜けているために設計がうまくできない、というケースも要件によってはあり得ます。そのような場合は、以下のような設計が考えられます。
親テーブルの作成設計

親テーブルの作成データ

記事(articles)と画像(photos)の親として投稿(posts)テーブルを作成します。
この設計方法でも、1つのコメントが記事と画像の両方に紐づかないように制約をかけることができません。厳密にいうと、1つのコメントは1つの投稿に対してのみ紐づきますが、1つの投稿に対して記事と画像の両方を紐付けることが出来てしまいます。
しかし、今回の例に挙げたような「記事や画像の投稿に対してコメントをつける」というケースであれば、背景となるサービスの仕様やプロジェクトの状況などにもよりますが、綺麗な設計と言えるのではないでしょうか?
紐づく対象のテーブルが頻繁に増加するような場合には特に考慮したい設計です。

4.テーブルの分割

そもそも、本当にcommentsを一つのテーブルに保存する必要性があるのか?というアプローチです。

テーブルの分割設計

要件として、commentsを一つのテーブルにまとめておいたほうが今後都合がよい、という場合もあります。
しかし、もしもそのような状況ではないのなら、最初からテーブル自体を分割しておくという選択肢も十分にあり得るのではないでしょうか?
現状で紐づく対象のテーブルが少なく、今後も増える可能性が低い場合には考慮したい設計です。

テーブルの分割データ

まとめ

サービスの仕様やプロジェクトの今後の見通しなど様々な要因が絡んでくるため、一概に「この方法が最強!」とは言えません。
結局のところはすべてケースバイケースとなってしまいますが、どの方法を用いて設計を行うかの判断基準を簡単にまとめます。

”まとめフロー図"

いかがでしたでしょうか?
ちなみに私は「3.親テーブルの作成」や「2.複数の関連テーブル」のアプローチが好みですが、アプリケーション側の実装をする際にjoinするテーブルが増えることを考えると、少し気が滅入ってしまいます。
以上、拙い解説ではありますが、少しでも設計の役に立てば幸いです。

About The Author

三澤悠人