优化MySQL中的多对多查询

时间:2017-02-11 17:41:03

标签: mysql sql

我有一个名为' items '的表,看起来像这样......

id | name
––––––––––––
1  | APPLES 
2  | BANANAS
3  | ORANGES
4  | PEARS

...以及一个名为“”的联结表,在这些项目之间创建多对多关系......

id | item1_id | item2_id
––––––––––––––––––––––––
1  | 1        |  2 
2  | 1        |  4
3  | 2        |  3
4  | 2        |  4
5  | 4        |  3

我有以下查询来查找与给定项目配对的项目......

SELECT * FROM items i
WHERE
  i.id IN (SELECT item1_id FROM pairs WHERE item2_id = 4)
OR
  i.id IN (SELECT item2_id FROM pairs WHERE item1_id = 4)

返回类似......

id | name
––––––––––––
1  | APPLES 
3  | ORANGES

...它完成了这项工作,然而,它的运行速度非常慢(使用大约100个项目的小型测试数据集,1000个已经占用大约75毫秒的配对)。

我的问题是 - 是否可以进一步优化以加快速度(例如使用连接而不是嵌套查询)?

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

我认为在pairs(item2_id, item1_id)pairs(item1_id, item2_id)上建立索引就足够了 - 两个单独的索引。

然而,MySQL有时候很难用子查询来优化IN。我会用exists

写这个
SELECT i.*
FROM items i
WHERE EXISTS (SELECT 1
              FROM pairs p
              WHERE p.item2_id = 4 AND p.item1_id = i.id
             ) OR
      EXISTS (SELECT 1
              FROM pairs p
              WHERE p.item1_id = 4 AND p.item2_id = i.id
             );

保证使用索引。

答案 1 :(得分:1)

内部查询优化器在创建执行计划方面做得很好,尽管您可以查看计划并识别瓶颈。以不同方式表达相同查询的事情通常不会在一天结束时产生巨大差异。即使是非常疯狂的查询,您也会对优化程序处理它们的程度以及同一查询的两个看似不同的表达式最终导致相同的事情感到惊讶。将其更改为使用联接可能会导致相同或类似的执行计划。

所以我首先要做的是在item1_id列上创建一个索引,在item2_id列上创建一个单独的索引。这将有助于提高那些条款的性能。然后,如果仍然不能满足您的要求,请查看the Optimization chapter in the MySQL docs(对于您正在使用的任何版本的MySQL),以便完全减少可能的策略。请注意,过早避免大量优化会使您受益,尤其是在应用程序很复杂的情况下。一旦您的应用程序处于大多数工作状态,您就能更好地识别和解决瓶颈问题。但在任何发展阶段,指数始终是一个简单而有价值的第一步。