MySQL查询 - 复杂的搜索条件

时间:2011-08-13 22:12:28

标签: 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           | 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。 location_type是beach(value - 1),mountain(value - 2)。

amenity_type是car(value - 1),bike(value - 2),football(value - 3)。

property_type是villa(value - 2),house(value - 3)

你能不能帮我获取SQL查询,选择property_id = location AND type_type = 2 AND amenity_type = 1 AND property_type = 3 AND property_type = 1即属性有海滩和山脉,汽车,别墅和房子

这只是我的属性搜索应用程序中的过滤器示例。这可以有n种组合。请分享一个共同的逻辑,它将加入所有这些表并进行优化,以搜索大约一百万条记录。

我还需要计算所有条件。请分享相同的查询。

[编辑计数]:

假设我得到(property_id,其中location_type = 1 AND property_type = 2 AND amenity_type = 1 AND property_type = 3 AND property_type = 1)为1500.我需要获得具有相同条件的计数和其他property_type,location_type, amenity_type。

例如:

1)(property_id,其中location_type = 1 AND location_type = 2 AND amenity_type = 1 AND property_type = 3 AND property_type = 1)AND location_type = 3

2)(property_id,其中location_type = 1 AND location_type = 2 AND amenity_type = 1 AND property_type = 3 AND property_type = 1)AND location_type = 4

3)(property_id与location_type = 1 AND location_type = 2 AND amenity_type = 1的计数 AND property_type = 3 AND property_type = 1)AND amenity_type = 2

4)(property_id与location_type = 1 AND location_type = 2 AND amenity_type = 1 AND property_type = 3 AND property_type = 1)和amenity_type = 3

等等。它给我带来了很大的开销。请帮忙。另请注意,location_types,amenity_type,property_type是动态的,即用户可以在主表中添加更多location_type,我需要获取更多location_types的计数。

3 个答案:

答案 0 :(得分:4)

在这种情况下,如果您有多个值,那么多个表没有任何问题。你在这里做的很好。这是您需要的查询:

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           

一旦你知道如何写就很容易:

  1. 为您需要的每个表/条件组合创建别名
  2. 确保所有人同时处理相同的property_id(l1.property_id = ...)
  3. 然后指定每个表/条件的条件
  4. 你也可以明确地使用“join”,但我发现上面的方法比较简单,对db引擎来说无关紧要。


    [从ypercube编辑显示JOIN语法]:

    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的评论:这个和初始语法应该在内部翻译成同一个查询,所以两者同样有效]


    [关于性能的编辑]一般来说,唯一(或者至少是最重要的)你需要担心的数据库性能是指数。您希望在每个表的property_id列上声明索引,也在您拥有的不同类型列上声明索引。这很关键。但是一旦你有了这个,只有几百万行,这应该很快 - 上面是一个非常复杂的查询,你有少于一GB的数据(考虑使用tinyint作为类型列)。别担心......别名(“作为X”)根本不是问题。


    您需要count of (property_id with location_type = 1 AND location_type = 2 AND amenity_type = 1 AND property_type = 3 AND property_type = 1) AND location_type = 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
    

    但我还没有测试过它。这应该为您提供多行,包含location_type和每行的计数(因此您可以在上面执行上面提到的所有查询)。

答案 1 :(得分:1)

select property_id from (
select property_id
from location
where location_type in (1,2)
group by property_id
having count(location_type) = 2
union all
select property_id
from amenities
where amenity_type = 1
group by property_id
union all 
select property_id
from property
where property_type in (1,3)
group by property_id
having count(property_type) = 2
) as t
group by property_id
having count(property_id) = 3

遵循我之前回答的相同逻辑,您可以使用union all来查找满足每个条件的property_id。在这种情况下,有3个查询。因此,您可以对此属性进行分组,如果计数等于3,则表示property_id满足所有条件。如果不满足单个标准,则不会返回property_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
)

它也适用于您的几个示例记录,但我确信在大型数据集上,此查询的性能会非常差。 ;)

答案 2 :(得分:0)

如果您需要执行该查询,最重要的部分是确保所有各个字段都具有索引。但是,由于每个表中的每个条目与其他表中的条目具有一对一的关系,因此最好只使用一个表。