# EAV (Entity-Attribute-Value) - 一般的にはアンチパターン ## データ構造 選択式の場合 ```mermaid erDiagram MEMBERS { int id PK string name } CUSTOM_FIELDS { int id PK string name } CUSTOM_FIELD_OPTIONS { int id PK int custom_field_id FK string value } MEMBER_CUSTOM_FIELD_CHOICES { int id PK int member_id FK int custom_field_id FK int custom_field_option_id FK } MEMBERS ||--o{ MEMBER_CUSTOM_FIELD_CHOICES : "has choices" CUSTOM_FIELDS ||--o{ CUSTOM_FIELD_OPTIONS : "has options" CUSTOM_FIELDS ||--o{ MEMBER_CUSTOM_FIELD_CHOICES : "can be selected" CUSTOM_FIELD_OPTIONS ||--o{ MEMBER_CUSTOM_FIELD_CHOICES : "selected by" ``` ## クロス集計の例 ```sql SELECT cf1.name AS field1_name, cfo1.value AS option1, cf2.name AS field2_name, cfo2.value AS option2, COUNT(mcc1.member_id) AS count FROM member_custom_field_choices AS mcc1 JOIN custom_fields AS cf1 ON mcc1.custom_field_id = cf1.id JOIN custom_field_options AS cfo1 ON mcc1.custom_field_option_id = cfo1.id JOIN member_custom_field_choices AS mcc2 ON mcc1.member_id = mcc2.member_id JOIN custom_fields AS cf2 ON mcc2.custom_field_id = cf2.id JOIN custom_field_options AS cfo2 ON mcc2.custom_field_option_id = cfo2.id WHERE cf1.name = '職務スキル' AND cf2.name = 'プロジェクト経験' GROUP BY field1_name, option1, field2_name, option2 ORDER BY field1_name, option1, field2_name, option2; ``` | field1_name | option1 | field2_name | option2 | count | | ----------- | ------- | ---------------- | ------- | ----- | | 職務スキル | Java | プロジェクト経験 | 3年以上 | 5 | | 職務スキル | Java | プロジェクト経験 | 1-3年 | 8 | | 職務スキル | Python | プロジェクト経験 | 3年以上 | 4 | | 職務スキル | Python | プロジェクト経験 | 1-3年 | 6 | | ... | ... | ... | ... | ... | ## 検討 - データ量の増加 - `member_custom_field_choices` テーブル - INDEX 貼ると INSERT 速度に影響 - JOINT のコスト - 対策:集計結果を非正規化[[キャッシュテーブル]]に保存しておくなど - クエリの複雑化 - 対策:定形のクロス集計を VIEW にして扱いやすくするなど - INDEX の制限 - INDEX が大きくなりがちで効果が限定的 - スキーマの制約が弱い - Validation が難しい - メタデータ管理が煩雑 ### EAVモデルが有効なケース - **データ項目が頻繁に変更される**:EAVは、属性が定期的に増減したり、自由設計項目が変更されるようなシナリオに対して柔軟に対応できます。 - **一部の属性しか参照しないケースが多い**:全属性を参照することが少なく、特定の属性のみ頻繁にアクセスする場合には、EAVの柔軟性が有効です。 - **スキーマ変更のコストが高い**:頻繁に新しい属性を追加するようなケースでは、スキーマの変更がほぼ不要なEAVが便利です。