我有一个DB结构,该结构旨在以易于扩展的方式存储特定对象的属性.
有一个“对象”表.
+----+----------------------
| id | ....(name, type, etc)
+----+----------------------
接下来,我有一个“属性”表.
+----+------+
| id | Name |
+----+------+
最后,一个“关系”表,用于将所有数据作为具有相应值的属性-对象对(作为主键)保留.
+--------+---------+-------+
| id_obj | id_attr | value |
+--------+---------+-------+
我需要一次获取满足多个条件的对象的ID.例如,我有一个名为“ Type”和“ City”的属性,我需要获取这些属性的对应值为“ Apartment”和“ City b”的对象的ID.
自昨天以来我将头撞墙之后,我设法提出了最好的解决方案(嗯,此查询的唯一好处是它实际上有效并获取了所需的记录):
SELECT objects.id
FROM (attributes INNER JOIN relations ON attributes.id = relations.id_attr)
INNER JOIN objects ON relations.id_obj = objects.id
WHERE objects.id
IN (
SELECT objects.id
FROM (attributes INNER JOIN relations ON attributes.id = relations.id_attr)
INNER JOIN objects ON relations.id_obj = objects.id
WHERE attributes.name = 'Type' AND relations.value = 'Apartment'
)
AND objects.id
IN (
SELECT objects.id
FROM (attributes INNER JOIN relations ON attributes.id = relations.id_attr)
INNER JOIN objects ON relations.id_obj = objects.id
WHERE attributes.name = 'City' AND relations.value = 'City b'
)
GROUP BY objects.id ASC
LIMIT 0 , 20
事实是,存储的数据量可能会变得有些大,而且恐怕所有这些子查询(可能需要指定一些10-15个过滤器),每个子查询都解析整个数据库,可能会导致严重的性能问题(并不是说即使我的SQL技能有限,我也可以肯定必须有一种更好的方法来完成我需要做的事情).
另一方面,对数据库进行大幅更改并不是真正的选择,因为与其一起使用的代码在很大程度上取决于当前的数据库结构.
有没有一种方法可以在单个查询中以有限的数量或不更改存储的数据结构的方式检查我需要的属性?
工作查询与上面的查询等效,但优化效果更好,归功于DRapp:
SELECT STRAIGHT_JOIN
rel.id_obj
from
relations rel
join attributes atr
on rel.id_attr = atr.id
where
( rel.value = 'Apartment' AND atr.name = 'Type' )
or ( rel.value = 'City b' AND atr.name = 'City' )
group by
rel.id_obj
having
count(*) = 2
limit
0, 20
解决方法:
这应该可以满足您的需求…每个“ OR” d where子句条件,您都可以继续添加为合格项目.然后,只需将“ Having”子句调整为与您允许的条件相同的数字即可…
我将关系表放在第一位,因为这样会在City的“值”或类型值上有一个较小的匹配集…确保在“ VALUE”列上的关系表上有一个索引.
SELECT STRAIGHT_JOIN
rel.id_obj
from
relations rel
join attributes atr
on rel.id_addr = atr.id
where
( rel.value = 'Apartment' AND atr.name = 'Type' )
or ( rel.value = 'Some City' AND atr.name = 'City' )
group by
atr.id_obj
having
count(*) = 2
limit
0, 20
如果要从该结果中获取所有实际的对象数据,则可以将其包装为…
select obj.*
from
( complete SQL statement above ) PreQuery
join Object obj on PreQuery.id_obj = obj.id