EAV(Entity–Attribute–Value,实体-属性-值)模型之所以“难写 SQL”,本质原因是:它把本来应该由表结构表达的信息,挪到了数据行里。这导致很多在普通关系模型中“天然支持”的查询,在 EAV 中都需要额外的拼接、聚合和转换。
下面从几个关键角度说明。
在普通表中:
users (
id,
name,
age,
email
)
查询很简单:
SELECT name, age, email
FROM users
WHERE age > 30;
在 EAV 中,可能变成:
entity_attr (
entity_id,
attr_name,
attr_value
)
同一个用户的 name / age / email 是三行数据:
| entity_id | attr_name | attr_value |
|---|---|---|
| 1 | name | Tom |
| 1 | age | 35 |
| 1 | tom@x.com |
要“还原成一行”,就必须 PIVOT(行转列):
SELECT
e1.entity_id,
e1.attr_value AS name,
e2.attr_value AS age,
e3.attr_value AS email
FROM entity_attr e1
JOIN entity_attr e2
ON e1.entity_id = e2.entity_id AND e2.attr_name = 'age'
JOIN entity_attr e3
ON e1.entity_id = e3.entity_id AND e3.attr_name = 'email'
WHERE e1.attr_name = 'name'
AND e2.attr_value > 30;
➡️ SQL 长度爆炸,可读性差
EAV 中 attr_value 通常只能是:
于是:
WHERE age > 30
可能变成:
CAST(attr_value AS INT) > 30
问题:
普通 SQL:
WHERE age > 30 AND city = 'Beijing'
EAV:
WHERE entity_id IN (
SELECT entity_id FROM entity_attr
WHERE attr_name = 'age' AND CAST(attr_value AS INT) > 30
)
AND entity_id IN (
SELECT entity_id FROM entity_attr
WHERE attr_name = 'city' AND attr_value = 'Beijing'
)
或大量 JOIN,性能和维护成本都高。
比如“按年龄分组统计人数”:
普通表:
SELECT age, COUNT(*)
FROM users
GROUP BY age;
EAV:
SELECT attr_value AS age, COUNT(*)
FROM entity_attr
WHERE attr_name = 'age'
GROUP BY attr_value;
但如果还要同时看 name、city,就又回到 PIVOT。
attr_value 是“大杂烩”EAV 的 SQL 往往:
这导致:
EAV 难写 SQL,是因为它用“数据”代替了“结构”,而 SQL 是为“结构化的表”设计的。
如果你愿意,我可以:
你想看哪一个?
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。