分面搜索的SQL查询(ALL IN)

时间:2018-02-10 12:42:39

标签: sql group-by inner-join one-to-many

好的,我们假设一些简单的数据库。 我们有pet table和pet_owner表,pet将其外键链接到pet_owner

 pet_owner:  
|--id---|-----name-----|  
|   1   |Michael Mayers|  
|   2   |John Doe      |  
|   3   |Markus Tsuker |  
|   4   |Bob Dilan     |  
|   5   |Simon Pegg    |  

 pet:
|--id---|----type---|---owner---|---name---|
|  1    |    dog    |     1     |Billy     |  
|  2    |    cat    |     1     |Willy     |
|  3    |   bird    |     1     |Dilly     |
|  4    |    dog    |     2     |Klaus     |
|  5    |    cat    |     2     |Boss      |
|  6    |    dog    |     3     |Shmat     |
|  7    |    dog    |     4     |Corin     |
|  8    |   fish    |     5     |Suzy      |
|  9    |   dog     |     1     |Mars      |

所以,简单的任务 - 我需要选择同时拥有CAT和DOG的人。这是分面过滤的一项微不足道的常见任务。

第一种方法:

SELECT
pet_owner.name
FROM pet_owner, pet
 WHERE
pet_owner.id = pet.owner AND
pet.type IN ('cat', 'dog')
GROUP BY pet_owner.name
HAVING (COUNT(DISTINCT pet.type) = 2);

第二种方法:

SELECT DISTINCT pet_owner.name
FROM pet_owner, pet T1, pet T2
WHERE pet_owner.id = T1.owner
 AND pet_owner.id = T2.owner
 AND T1.type = 'cat'
 AND T2.type = 'dog';

问题:

  1. 这个任务有没有更好的SQL查询(我想,有)?
  2. 如果没有,哪个更快?对于10,100,1000个独特的过滤器?

1 个答案:

答案 0 :(得分:1)

从不FROM子句中使用逗号; 始终使用正确的JOIN语法。这是建议,所以你的代码看起来像是在21世纪写的,与实际问题无关。

这个问题的正常答案是说"试试你的数据,看看哪个更快"。

但是,对于您的特定问题,聚合方法更好。

让我承认偏见。无论如何,我更喜欢聚合方法。只需要对三个宠物进行一次简单的修改即可以改变标准 - 比如需要三只宠物,或者检查鸟类和狗只。甚至,猫和狗,但不是鸟。

在这种情况下更好的原因是select distinct。无论如何,这基本上都会在连接之上进行聚合。更糟糕的是,人们可以拥有多只宠物,因此连接生成的行数可能会大于原始行数。

事实上,有人可能会有一个小狗工厂,其中有几只宠物猫被扔进去,并且真正使用连接来甩掉查询的性能。小狗工厂对聚合查询的性能影响很小。

如果你的数据开始时是不同的(人们只允许一种类型的宠物)并且你正在寻找两个特定的数据,那么join查询通常会有更好的表现(它仍然取决于其他因素)数据和数据库优化器)。即便如此,出于上述原因,我仍默认使用这些类型查询的聚合方法。

我还要注意,我在生活中写过一些非常复杂的问题。我不认为我曾经写过一个有1000个连接的连接。如果您正在查看那么多项目,那么GROUP BY将是您的选择。查询会简单得多。