使用INNER JOIN或EXISTS来查找属于m2m关系的几个更好吗?

时间:2012-10-25 07:37:26

标签: mysql sql performance many-to-many

给定m2m关系:项目类别我有三个表:

  • 项目
  • 类别
  • items_categories ,其中包含对
  • 的引用

我想找到一个属于所有给定类别集的项目:

Find Item 
belonging to a category in [1,3,6] 
and belonging to a category in [7,8,4] 
and belonging to a category in [12,66,42]
and ...

我可以通过两种方式在mySQL中实现这一目标。

选项A:内部联合:

SELECT id from items 
INNER JOIN category c1 ON (item.id = c1.item_id)
INNER JOIN category c2 ON (item.id = c2.item_id)
INNER JOIN category c3 ON (item.id = c3.item_id)
...
WHERE
c1.category_id IN [1,3,6] AND
c2.category_id IN [7,8,4] AND
c3.category_id IN [12,66,42] AND
...;

选项B:EXISTS:

SELECT id from items
WHERE
EXISTS(SELECT category_id FROM category WHERE category.item_id = id AND category_id in [1,3,6] AND
EXISTS(SELECT category_id FROM category WHERE category.item_id = id AND category_id in [7,8,4] AND
EXISTS(SELECT category_id FROM category WHERE category.item_id = id AND category_id in [12,66,42] AND
...;

两种选择都有效。问题是:哪个是大项目表最快/最优的?或者是否有一个我缺少的选项C?

4 个答案:

答案 0 :(得分:11)

选项A

JOIN优于EXIST,因为它会更有效地使用索引,尤其是在大型表的情况下

答案 1 :(得分:11)

一般来说,JOIN效率更高。

但是,需要注意的一点是,连接可以在输出中产生重复的行。例如,如果项目ID在类别1和3中,则第一个JOIN将导致id为123的两行。如果项目ID 999在类别1,3,7,8,12和66中,则将在结果中获得999的 8个行(2 * 2 * 2)。

重复行是您需要注意和处理的事情。在这种情况下,您可以使用select distinct id...。但是,通过复杂的查询,消除重复可能会变得更加复杂。

答案 2 :(得分:2)

您正在选项B 中使用加入,在选项B 中使用subquery。区别在于:

在大多数情况下,JOIN比子查询更快,并且子查询的速度非常快。

在JOIN中,RDBMS可以创建一个更适合您的查询的执行计划,并且可以预测应该加载哪些数据以进行处理并节省时间,这与子查询不同,后者将运行所有查询并将所有数据加载到做处理。

子查询的好处是它们比JOIN更具可读性:这就是大多数新SQL用户更喜欢它们的原因;这是简单的方法;但是在性能方面,JOINS在大多数情况下都更好,即使它们也不难阅读。

答案 3 :(得分:1)

 select distinct `user_posts_id` from `user_posts_boxes`
     where `user_id` = 5 
     and 
     exists (select * from `box` where `user_posts_boxes`.`box_id` = `box`.`id` 
     and `status` in ("A","F"))
     order by `user_posts_id` desc limit 200;



 select distinct `user_posts_id` from `user_posts_boxes`
 INNER JOIN box on box.id = `user_posts_boxes`.`box_id` and box.`status` in ("A","F")
 and box.user_id = 5
 order by `user_posts_id` desc limit 200

我尝试了两个查询,但是上面的查询对我来说工作更快,两个表都有大数据集。几乎“ user_posts_boxes”有400万,盒子为150万。

第一个查询耗时= 0.147毫秒 第二次查询几乎= 0.5到0.9 MS

但是我的数据库表是inno db,并且还具有物理关系。

所以我应该继续存在,但这还取决于您的数据库结构如何。