24

给定 m2m 关系:items-categories我有三个表:

  • 物品
  • 类别
  • 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:存在:

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
...;

两种选择都有效。问题是:对于大型项目表,哪个是最快/最优化的?还是缺少 OPTION CI?

4

5 回答 5

15

选项 A

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

于 2012-10-25T07:40:42.517 回答
15

JOIN一般来说, A更有效。

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

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

于 2012-10-25T07:51:32.747 回答
3
 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 万个,boxes 是 150 万个。

第一次查询花费 = 0.147 毫秒 第二次查询几乎 = 0.5 到 0.9 毫秒

但是我的数据库表是 inno db 并且也应用了物理关系。

所以我应该选择存在,但这也取决于你的数据库结构。

于 2018-07-28T15:53:46.383 回答
2

您在Option A中使用 Join ,在Option B中使用子查询。区别在于:

在大多数情况下,JOIN 比子查询快,而且子查询更快的情况很少见。

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

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

于 2012-10-25T07:43:13.910 回答
0

另外,请从 Mysql 文档中阅读内容,该文档讨论了这一点以及以前版本中的新更改以及 MySql 的实际执行方式exists

如果子查询满足上述条件,MySQL 会将其转换为半连接(或者,在 MySQL 8.0.17 或更高版本中,如果适用,则为反连接)并从这些策略中做出基于成本的选择:

将子查询转换为联接,或使用表拉出并将查询作为子查询表和外部表之间的内部联接运行。表拉出将表从子查询拉出到外部查询。

...

于 2021-12-28T06:46:21.273 回答