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           
一旦你了解了如何:

  • 为所需的每个表/条件组合创建别名
  • 确保所有地址都同时指向相同的属性\u id(l1.property\u id=…)
  • 然后为每个表/条件指定条件
  • 您也可以显式地使用“join”,但我发现上面的方法更简单,对db引擎来说应该无关紧要


    [从显示联接语法的文本中编辑]:

    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种物业类型。你能帮我解决不同组合的问题吗