0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SQLアンチパターン-5章 EAV-まとめ

Posted at

EAVについて

例えばイシューというデータを扱うモデルを考えてみましょう。

イシューモデル

issue_id title
1 フォームが送れない
2 ログインができない
3 決済ができない

イシューそれぞれに対して、例えば「いつ起きたか」「どのバージョンのコミットに関係するものか」「詳しい内容は何か」といった情報を付与したいと考えたとします。

イシュー属性要素モデル

issue_id attr_name attr_value
1 status NEW
1 description 全ての情報を入力して、送信ボタンを押しても、ページが遷移しません。
1 version_affected 1.5

このように、汎用的な属性をテーブルで管理する設計をEAV(Entity-Attribute-Value)といいます。このようなテーブルを作成する事で

  • イシューにつける情報量を減らせる(列を減らせる)
  • 新しい属性を追加しようとした時に、イシュー属性要素モデルの行を増やせば良いだけ
  • 仮にイシューモデルのテーブルだけで属性要素を扱おうとした時に、NULL値が入る事を防ぐ事ができる。例えば、イシューによってはdescriptionは必要なかったり。(極論ですが・・・)

EAVを使う事のデメリット

属性に必須という設定をする事ができない

attr_name毎に、その値が必須なのかどうか、設定することはできません。

データ型を上手く扱えない

attr_valueに入る値はattr_nameによって変わります。つまりデータ型も変わります。
そのため、attr_valueにはどのような型の情報でも入れられるようにしなければなりません。
そのため、attr_valueは文字列型で扱うのがスタンダードな設定となります。
attr_value列を拡張して、列を増やし、それ毎に型を設定する方法もありますが、クエリが冗長になってしまいます。

参照整合性を強制する事ができない

後ほど執筆

属性名の規定を設定できない

原則的にはattr_nameにはどんな情報も入れる事ができる。
つまりissue_dateなのか、date_issueなのか、それを定めるためにまた別の参照テーブルを作成することが必要になってしまいます。

行を再構築しなければならない

EAVを使わなければ、イシューモデルに対して属性要素が全て格納されています。
EAVを使った場合、イシュー属性要素テーブルを結合するために、データをJOINする必要があります。必要な情報を結合しようとすると、その分クエリもJOIN文が増え、実行コストが増えていってしまいます。

EAVを使うのはどういう時か

EAVを使う事を正当化できるようなケースはまだ思いつきません・・・
「属性要素が10個くらいあるが、属性要素自体はこれ以上増えないと確定している」時でしょうか・・・

EAVの解決方法

シングルテーブル継承

全ての属性要素を、別のテーブルとかに分けず、一つにまとめるという事。
つまり、冒頭の例でいうと、イシュー属性要素モデルを作成せず、イシューモデルで全て扱うようにする、という事である。
しかし、この場合、属性要素を増やす時には列を増やす必要があります。
また、イシューの種類によっては不必要な列も出てきてしまう可能性もあります。

具象テーブル継承

シングルテーブル継承に改良を加えたものです。
イシューの種類によって不必要な列が出てきてしまう可能性があるので
そのイシューの種類毎に属性要素のテーブルを作成するという方法が良さげです。

例えばイシューにも「ユーザー側」と「管理画面側」と2種類に分ける事ができたとします。
その際、IssueUserAttrとIssueAdminAttrの2種類のモデルを作成する事で
属性要素をそれぞれ扱う事ができ、イシューの種類によって不必要な列が生まれる、という事を防ぐ事ができます。

クラステーブル継承

具象テーブル継承にて、IssueUserAttrとIssueAdminAttrの2種類のモデルを作成した際に、両方のモデルに共通の要素(列)ができることもあるかもしれません。
その際は共通の要素を抜き出して、基底となるモデルを作ることもできます。
クラスのように、親クラスを作成して、そこからサブクラスを作成するようなイメージですね。

半構造化データ

LOB(Large Object型の総称)列を追加し、XMLやJSONデータとして扱う方法です。
テーブルに分けてわざわざ行を増やしたり、列を増やしたりする必要がありません。
一方で、LOB列で扱うデータを元に検索などするにはとても不向きになります。
ただ出力するというだけでしか扱われないような情報であれば良いのですが・・・

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?