# 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が便利です。