【问题标题】:Optimising many-to-many query in MySQL优化 MySQL 中的多对多查询
【发布时间】:2017-06-29 23:07:19
【问题描述】:

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

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

...和一个名为“pairs”的联结表,在项目之间创建多对多关系...

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 毫秒)。

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

感谢您的帮助。

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

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

    所以我首先要做的是在 item1_id 列上创建一个索引,并在 item2_id 列上创建一个单独的索引。这将有助于提高那些 where 子句的性能。然后,如果这仍然不能满足您的要求,请查看the Optimization chapter in the MySQL docs(无论您使用的是哪个版本的 MySQL),以了解可能的策略的完整列表。请注意,过早地避免重度优化会让您受益,尤其是在您的应用程序很复杂的情况下。一旦您的应用程序处于大部分工作状态,您将能够更好地识别和解决瓶颈。但在任何开发阶段,索引始终是一个简单而有价值的第一步。

    【讨论】:

    • 这有很大的不同。执行时间从约 74 毫秒降至约 3 毫秒!我以前从未使用过索引,并且知道 MySQL 类似地优化不同表达的查询很有帮助。谢谢! :)
    • @teadog 只是不要陷入索引一切的陷阱,创建索引where they help。 PS 对于更大的数据集,您可能还想尝试在 (item1_id,item2_id) 上使用单个多列索引与我在此处描述的两个单列索引(我不会同时执行所有这三个索引除非有真正的需要,否则有时间)。
    【解决方案2】:

    我认为在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
                 );
    

    这些保证使用索引。

    【讨论】:

    • 添加索引后,EXISTS实际上比IN慢一点。非常感谢。毫无疑问,下次会有所帮助:)
    • @teadog 。 . .您实际上必须在大型数据集上进行测试。
    • 啊哈,谢谢!无法投票,因为我是新手,抱歉。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    • 2020-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多