MySQL查询-复杂的搜索条件
我有一个带有以下结构的表“位置”:MySQL查询-复杂的搜索条件,mysql,optimization,Mysql,Optimization,我有一个带有以下结构的表“位置”: id | property_id | location_type 1 | 1 | 1 2 | 1 | 2 3 | 2 | 1 4 | 3 | 2 5 | 4 | 1 6 | 4 | 2 id | property_id | amenity_type 1 | 1 | 1 2 | 1
id | property_id | location_type
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 3 | 2
5 | 4 | 1
6 | 4 | 2
id | property_id | amenity_type
1 | 1 | 1
2 | 1 | 3
3 | 2 | 2
4 | 3 | 4
5 | 4 | 1
6 | 4 | 3
id | property_id | property_type
1 | 1 | 2
2 | 1 | 3
3 | 2 | 2
4 | 3 | 4
5 | 4 | 2
6 | 4 | 3
我还有另一张桌子“便利设施”,其结构如下:
id | property_id | location_type
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 3 | 2
5 | 4 | 1
6 | 4 | 2
id | property_id | amenity_type
1 | 1 | 1
2 | 1 | 3
3 | 2 | 2
4 | 3 | 4
5 | 4 | 1
6 | 4 | 3
id | property_id | property_type
1 | 1 | 2
2 | 1 | 3
3 | 2 | 2
4 | 3 | 4
5 | 4 | 2
6 | 4 | 3
我有另一个表“property”,其结构如下:
id | property_id | location_type
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 3 | 2
5 | 4 | 1
6 | 4 | 2
id | property_id | amenity_type
1 | 1 | 1
2 | 1 | 3
3 | 2 | 2
4 | 3 | 4
5 | 4 | 1
6 | 4 | 3
id | property_id | property_type
1 | 1 | 2
2 | 1 | 3
3 | 2 | 2
4 | 3 | 4
5 | 4 | 2
6 | 4 | 3
id-是相应表的主键。property_id是我的数据库的属性id(外键)。位置类型为海滩(值-1),山地(值-2)
市容类型为汽车(价值-1)、自行车(价值-2)、足球(价值-3)
物业类型为别墅(价值-2)、住宅(价值-3)
请您帮助我获取SQL查询,以选择位置为1、位置为2、舒适度为1、属性为3、属性为1的属性id,即属性具有海滩、山脉、汽车、别墅和房屋
这只是我的属性搜索应用程序中的一个过滤器示例。这个可以有n个组合。请共享一个通用逻辑,它将连接所有这些表,并进行优化以搜索大约一百万条记录
我还需要计算所有的条件。请共享相同的查询
[为计数而编辑]:
假设我将(位置为1、位置为2、设施为1、属性为3、属性为1的属性为id)的计数设为1500。我需要获得具有相同条件和其他属性类型、位置类型、设施类型的计数
例如:
1) (位置类型为1、位置类型为2、设施类型为1、属性类型为3、属性类型为1的属性id)和位置类型为3的计数
2) (位置类型为1、位置类型为2、设施类型为1、属性类型为3、属性类型为1的属性id)和位置类型为4的计数
3) (位置类型为1、位置类型为2、设施类型为1的物业id)计数
物业类型=3,物业类型=1)和便利设施类型=2
4) (位置类型为1,位置类型为2,设施类型为1,属性类型为3,属性类型为1的属性id)和设施类型为3的计数
等等。我的开销很大。请帮忙。另外,请注意位置类型、设施类型、属性类型是动态的,即用户可以在主表中添加更多的位置类型,我需要获取更多位置类型的计数。如果需要进行该查询,最重要的部分是确保所有不同字段都有索引。但是,由于每个表中的每个条目都与其他表中的条目有一对一的关系,因此最好只使用一个表。在这样的情况下,如果您有多个值,那么多个表没有问题。你在这里做的很好。以下是您需要的查询:
select distinct l1.property_id
from location as l1, location as l2,
amentities as a,
properties as p1, properties as p2
where l1.property_id = l2.property_id
and l1.property_id = a.property_id
and l1.property_id = p1.property_id
and l1.property_id = p2.property_id
and l1.location_type = 1
and l2.location_type = 2
and a.amenity_type = 1
and p1.property_type = 3
and p2.property_type = 1
一旦你了解了如何:
[从显示联接语法的文本中编辑]:
SELECT p.id
FROM
property AS p
JOIN
location AS l1
ON l1.property_id = p.id
AND l1.location_type = 1
JOIN
location AS l2
ON l2.property_id = p.id
AND l2.location_type = 2
JOIN
amentities AS a1
ON a1.property_id = p.id
AND a1.amenity_type = 2
JOIN
properties AS p1
ON p1.property_id = p.id
AND p1.property_type = 3
JOIN
properties AS p2
ON p2.property_id = p.id
AND p2.property_type = 1
[来自ac的评论:这和初始语法应该在内部翻译成同一个查询,因此两者都同样有效]
[edit about performance]通常,要获得良好的数据库性能,您需要担心的唯一(或至少是到目前为止最重要的)事情是索引。您需要在每个表的property_id列上声明一个索引,也可以在您拥有的不同类型列上声明一个索引。这是至关重要的。但是一旦你有了它,对于几百万行,这应该是很快的——上面的查询不是一个非常复杂的查询,并且你的数据少于GB(考虑对类型列使用tinyint)。别担心。。。别名(“as X”)根本不是问题
[为计数而编辑]对于(位置为1、位置为2、舒适性为1、属性为3、属性为1、位置为X的属性为id)和位置为X的计数
select lx.location_id, count(l1.property_id)
from location as l1, location as l2, location as lx
amentities as a,
properties as p1, properties as p2
where l1.property_id = l2.property_id
and l1.property_id = a.property_id
and l1.property_id = p1.property_id
and l1.property_id = p2.property_id
and l1.property_id = lx.property_id
and l1.location_type = 1
and l2.location_type = 2
and a.amenity_type = 1
and p1.property_type = 3
and p2.property_type = 1
group by lx.location_type
但我还没有测试过。这将为您提供多行,其中包含位置类型和每行的计数(因此您可以在一行中完成上面给出的所有查询)
按照我前面回答的相同逻辑,您可以使用union all来查找满足每个条件的属性_id。在本例中,有3个查询。因此,您可以对该属性进行分组,如果计数等于3,则表示该属性_id满足所有条件。如果哪怕只满足一个条件,也不会返回属性id
编辑。
另一种可能的解决办法:
select property_id
from location
where location_type in (1,2)
group by property_id
having count(location_type) = 2
and property_id in (
select property_id
from amenities
where amenity_type = 1
group by property_id )
and property_id in (
select property_id
from property
where property_type in (1,3)
group by property_id
having count(property_type) = 2
)
它也适用于您的少数示例记录,但我确信在大型数据集上,此查询的性能会非常差。;) 你能把三张桌子合并成一张桌子吗?这将减轻连接的性能损失。实际上,最初它是一个单表。它的值如下:id | property | id | location | type |舒适| type | property | type 1 | 1 | 1,2,3 | 2,3 | 1,2。但是,对于我来说,提取位置类型为1和3、设施类型为2的属性id变得越来越困难。您可以将列设置为
int
-这将提高索引的性能。这不是一对一的关系。如您所见,属性_id 1可以有多个位置类型、多个基本类型和多个属性类型。啊,在这种情况下,您是否考虑过使用集合来存储每一类属性@Zack Bloom:使用集合或枚举不是标准的SQL,MySQL对它们的实现很差,这可能会导致错误。我的经验法则是,除非你真的知道自己在做什么,否则永远不要使用枚举或集合。谢谢!我有大约15种不同的地点类型、12种便利设施和10种物业类型。你能帮我解决不同组合的问题吗