SQLアンチパターン-7章 マルチカラムアトリビュート-まとめ


テーブルを設計する際に、属性の値が複数ある場合はどうしましょうか。
Wordpressを例にしてみます。
記事には複数のカテゴリ、タグがつける事ができますよね。
DB上ではそれらをどうやって表現するのでしょうか。

下記のようなテーブル設計はアンチパターンとなります。

post_id title category_1 category_2 category_3
1 今日は晴れ 日常 お出かけ 家族
2 今日は曇り 日常
3 今日は雨 日常 家事

テーブル定義の更新する時

この場合、カテゴリーが増えたらどうなるでしょう。
テーブル定義を更新しなければなりません。
また、NULL値も入ってしまうので、無駄な列が存在してしまいます。
更新する時はテーブルをロックする必要が出てくるかもしれません。

検索する時

複数の列からある値を元に検索する場合、下記のようなSQLになります。

SELECT * FROM Posts
WHERE (category_1 = "日常" OR category_2 = "日常" OR category_3 = "日常") 
AND 
WHERE (category_1 = "家族" OR category_2 = "家族" OR category_3 = "家族") 

このような検索クエリは冗長です。

更新を行う時

値の上書きを防ぐためには、まず SELECT文で値が入っていないかを確かめ
次にUPDATE文を発行することになります。

値の一意性

category_1 category_2 category_3 それぞれに対して
値が重複しないようにするためには手間がかかります。

このアンチパターンが許されるケース

  • category_hogehoge が増えないという事
  • category_hogehoge のそれぞれがそれぞれの意味を個別に持っているという事

以上に当てはまる場合はこのアンチパターンを用いても大丈夫かもしれません。

解決策

従属テーブル

今回の例では、post_id を外部キーとして持つCategoryテーブルを作成すれば良いでしょう。
あるカテゴリが紐づけられている記事にどのようなものがあるか、検索する事が容易になります。

必要な数だけカテゴリを記事に対して紐づける事ができます。
また、PRIMARY KEY制約 もしくは UNIQUE制約を利用する事で、同じカテゴリが記事に結びつけられるといった事も防ぐ事ができます。