💭

EAVは本当にアンチパターンなのか?

に公開

1.はじめに

EAV(Entity Attribute Value)モデルというデータモデルをご存知でしょうか? EAVモデルは、「SQLアンチパターン(第1版)」の5章でアンチパターンとして紹介されており、あまり良いイメージを持たれていないエンジニアの方もいらっしゃるのではないでしょうか。確かにSQLアンチパターンで紹介されているEAVモデルの素朴な実装はデメリットも多く、素直に採用するのは注意が必要です。しかし、この記事で紹介する改良版のEAVモデルは、特定のユースケース(大規模動的属性管理など)を満たす場合、十分有力な選択肢になりうるデータモデルであると考えています。この記事では、素朴EAVモデルの課題について改めて振り返った上で、そのデメリットを克服した改良EAVモデルをご紹介します。

対象読者

  • アンチパターンと呼ばれる設計パターンでも、要件などの事情で取り組む必要のあるかた
  • 設計やアーキテクチャのトレードオフに関心のあるかた
  • EAVモデルで実際に開発・運用をしているかた

記事を読むメリット

  • 実用的なEAVの実装パターンを知ることができる
  • 実務でのデータ設計の難しさを理解できる

結論

  • 素朴EAVモデルには確かに多くの弱点があるが、改良EAVモデルはその多くを克服している
  • 本質的に難しいのは大規模動的属性管理という要件自体

2.素朴EAVモデルの実装と限界

なぜEAVモデルを採用したくなるのか?

データモデル設計において、将来に対する拡張性とシンプルさ(YAGNI)はよくみられるトレードオフです。EAVモデルが必要になるケースは、システムに高い拡張性が要求される場合にしばしば発生します。例えば、アパレルブランドのECサイトを構築しているとします。あるTシャツ(Entity)は、サイズ・色・価格などの属性(Attribute)を持っています。一方で、あるカバンは収納量やポケットの数などの属性を持ちます。これらの各属性を製品テーブルの1カラムとして実装した場合、そのブランドが新たなカテゴリを追加したり、既存製品に対して追加の属性を増やしたい場合に、テーブル定義の変更を伴う開発が発生します。
しかし、EAVモデルなどの拡張性を備えたデータモデルでは、このような属性追加をシステム上の設定(メタデータ)として管理することで、システム改修なしに実現します。それにより、製品追加のリードタイムを短縮し、ビジネスに貢献することができます。
同様の要件は、電子カルテの検査項目やCRMのカスタムフィールド管理など、EC以外の領域でも見られます。つまり、アンチパターンとして紹介されるEAVであっても、実務では避けられないケースが存在するのです。

サンプル実装

ここでは、まず非常に素朴なEAVモデルの実装パターンによるテーブル定義の例をご紹介します。

CREATE TABLE product (
    product_id BIGINT PRIMARY KEY,
    code VARCHAR NOT NULL
);
CREATE TABLE attribute (
    attribute_id BIGINT PRIMARY KEY,
    product_id BIGINT NOT NULL REFERENCES product(product_id),
    name VARCHAR NOT NULL,
    value TEXT
);

製品(product)テーブルが、EAVにおけるE(Entity)を表現し、それに属性(attribute)テーブルがnameとvalueというKey Valueの形式で、A(Attribute)とV(Value)をそれぞれ表現します。これにより、あらかじめテーブル定義を用意しなくても、動的に属性を増やすことを実現することができます。

素朴EAVはなぜ“アンチパターン”と呼ばれるのか?

上記の素朴EAVモデルには、主に3つのデメリットが存在します。

1.SQLのデータ型を使えない

素朴EAVモデルでは、あらかじめ値(Value)にどのような値が入るのかわからないためデータ型をTEXTなどの汎用的な型でしか設定できません。そのため、データフォーマットの統一化や整合性の面でしばしば課題が出ます。例えば、販売日のような日付の情報を属性として管理する場合に、現状では"2025-09-28"とも"2025年9月28日"とも入力ができてしまいます。

2.参照整合性を強制できない

ECやPIMでは、しばしばマスタ管理されたデータを属性として紐付けたいケースが発生します。例えば、あるTシャツの写真(メディアファイル)を紐づけて表示させたいなどの要件です。このような場合、メディアファイルは外部のストレージ(S3など)やDB上にマスタとして格納した上で、外部キー参照によって参照するのがRDB的な解決方法です。しかし、素朴EAVモデルでは、属性ごとに外部参照すべきなのかカラムに実際の値を持つべきなのかが異なるため、単純に外部キー参照によって制約をかけることができません。

3.検索パフォーマンスの劣化を招きやすい

EAVモデルでは、基本的にEntity数×Attribute数でレコード数が増加します。そのため、大規模化した際に、しばしば検索パフォーマンスという点で課題を招きます。これが、数百程度のEntityに数十のAttributeが紐づく程度なら良いのですが、数十万のEntityに数千のAttributeが紐づくようなケースでは十分なパフォーマンスを維持することは困難です。

3.素朴EAVをどう改良できるか?

ここまで、素朴実装のEAVモデルの概略とそのデメリットについてみてきました。今度は、これらのデメリットについて改良した改良版のEAVモデルについて紹介します。

改良EAVモデル1: 型付EAVモデル

まず、素朴EAVモデルの「1.SQLのデータ型を使えない」、「2.参照整合性を強制できない」というデメリットを解消した型付EAVモデルをご紹介します。

CREATE TABLE product (
    product_id BIGINT PRIMARY KEY,
    code VARCHAR NOT NULL
);
CREATE TABLE attribute (
    attribute_id BIGINT PRIMARY KEY,
    product_id BIGINT NOT NULL REFERENCES product(product_id),
    name VARCHAR NOT NULL,
    type VARCHAR NOT NULL
);
CREATE TABLE value_datetime (
    value_datetime_id BIGINT PRIMARY KEY,
    attribute_id BIGINT NOT NULL REFERENCES attribute(attribute_id),
    timestamp datetime
);
CREATE TABLE value_media (
    value_media_id BIGINT PRIMARY KEY,
    attribute_id BIGINT NOT NULL REFERENCES attribute(attribute_id),
    media_id BIGINT NOT NULL REFERENCES media(media_id)
);
CREATE TABLE media (
    media_id BIGINT PRIMARY KEY,
    content BYTEA
);

型付EAVモデルでは、属性の型(type)ごとに格納するテーブル(※1)をわけ、型ごとにSQLのデータ型を適切に設定します。こうすることにより、日付のデータはtimestamp、数値のデータはintやnumeric(十進数)などの最適な型で設定することができデータの信頼性を大幅に向上することができます。また、メディアファイルなどの参照データについても外部キー参照制約をつけることができ、参照整合性をDBのレベルで担保することができます。

改良EAVモデル2: EAVモデル+検索エンジン(OpenSearchなど)

次に、素朴EAVモデルの「3.検索パフォーマンスの劣化を招きやすい」という課題に取り組みます。ここでは、データ更新は安全性やトランザクション制御のために、RDB上のEAVモデルに実施。それを非正規化した形で検索エンジン(OpenSearchなど)に同期することで、最終的に検索を実行するユーザに対しては高いパフォーマンスで応答することを実現します(※2)。

概略図

改良EAVモデル3: ハイブリットモデル(型付EAVモデル+検索エンジン)

上記では、型付EAVモデルと検索エンジン併用モデルを別モデルとして紹介しましたが、これらを両方採用したハイブリットモデルを実装可能です。

各モデルの比較

ご紹介した改良モデルと素朴モデルを比較すると、下記のような星取表になります。ハイブリットモデルでは、素朴EAVモデルの3つのデメリットがうまく解消されています。

型安全性 参照整合性 検索パフォーマンス
素朴EAVモデル × ×
型付EAVモデル ×
EAVモデル+検索エンジン × ×
ハイブリットモデル

4.改良しても消えない“動的属性管理”の壁

上記で、ご紹介したハイブリットモデルは、素朴EAVモデルの多くの弱点をうまく克服しており、設計上有力な選択肢になっているのではないでしょうか。しかし、このようなEAVモデルを採用したい背景となる大規模動的属性管理の要件は、残念ながらこれだけでは解決し切ることはできません。現代のシステムは、単一のシステム内でデータを登録し、参照するだけというシステムは少なく、基本的に複数の外部システムと連携して初めてその価値を発揮します。属性を動的に管理するという要件が入ると、これらの動的な性質が各システムに対するインターフェースに波及します。例えば、更新フォームはどうでしょうか?静的に属性を管理している場合、その属性を管理する更新フォームは簡単なHTMLで実装できますが、動的に属性が増えたり減ったりする前提だと、あらかじめ更新フォームを固定で実装することができないため、メタ情報としてどのような属性を登録することができるのかを返すAPIが必要になったり、複雑さが一気に増します。
このような動的属性管理のメタ情報に関する課題は、SQLアンチパターンで紹介されているサブタイプによるモデリングや半構造化モデリング(JSONカラムなど)でも同様に問題になります。EAVモデルにまつわる難しさの一部は、動的属性管理という要件全般に共通する設計・実装難易度に起因するものではないでしょうか。

5.まとめ

EAVモデルは確かに素朴な実装では多くの欠点があり、アンチパターンとして紹介されるのも理解できます。しかし、型付きEAVや検索エンジンとの併用といった改良を施すことで、その欠点は多く克服できます。そして実務上、本当に難しいのはEAVそのものではなく「大規模動的属性管理」という要件そのものです。

要件を正しく理解し、どの改良パターンを選択するかを検討することこそが、EAVを扱う設計の肝だと言えるでしょう。

6.参考文献

補足

※1: 型ごとにカラムだけを分けて、複数の型を1テーブルで管理する設計パターン(シングルテーブル継承パターン)も選択肢の一つとしてありますが、valueテーブルはレコード数が肥大化する傾向が強いので、ここではあらかじめテーブルを分ける前提で実装例を作成しています。
※2: 検索エンジンはドキュメントモデルのため、EAVモデルとは言えないのではというご意見もあるかと思いますが、更新の整合性と参照のスピードを両立する設計パターンとして、別のストレージにデータを格納する方式は有力な選択肢としてご紹介しています。

Discussion