【问题标题】:Using MySQL "in" causes loop?使用 MySQL“in”会导致循环?
【发布时间】:2012-02-06 02:05:21
【问题描述】:

当我隔离这个查询时:

SELECT `Tagged`.`contact_id` 
FROM contacts_tags AS Tagged LEFT JOIN tags AS Tag ON (`Tagged`.`tag_id` = `Tag`.`id`)  
WHERE `Tag`.`id` = 137;

我明白了:

+------------+
| contact_id |
+------------+
|       3519 |
|      17080 |
+------------+

但是当我使用“IN”将它与更大的查询结合起来时,我会得到某种递归循环,并且我的数据库开始消耗处理能力,直到超时。

SELECT `Contact`.*
FROM `contacts` AS `Contact` 
WHERE `Contact`.`id` in 
(SELECT `Tagged`.`contact_id` 
FROM contacts_tags AS Tagged LEFT JOIN tags AS Tag ON (`Tagged`.`tag_id` = `Tag`.`id`)  
WHERE `Tag`.`id` = 137 );

这会一直运行,直到我重置服务器。

但是当我手动列出第一个查询响应时它可以工作:

SELECT `Contact`.*
FROM `contacts` AS `Contact` 
WHERE `Contact`.`id` in 
(3519, 17080);

有什么区别?

【问题讨论】:

  • SQL 不会陷入循环,除非您明确使用循环。如果运行时间过长,则可能意味着查询非常昂贵。您的数据库中有多少数据可以运行它?
  • 表中有哪些索引?
  • 另外,为了提高性能,请考虑对子查询使用 JOIN,而不是 IN (...)。例如,查看此问题的已接受答案:stackoverflow.com/questions/8713476/…

标签: mysql cakephp loops has-and-belongs-to-many


【解决方案1】:

MySQL 的当前 GA 版本在优化子查询方面真的很糟糕。有可能正在为Contacts 中的每一行执行子查询。如果您运行EXPLAIN your_query_here,您可以看到这一点。您会看到子查询已被标记为 DEPENDENT SUBQUERY

这不是一个很好的解决方案,但这样的事情可能会奏效。

"SELECT `Contact`.*
FROM `contacts` AS `Contact` 
WHERE `Contact`.`id` in 
(SELECT * FROM (SELECT `Tagged`.`contact_id` 
FROM contacts_tags AS Tagged LEFT JOIN tags AS Tag ON (`Tagged`.`tag_id` = `Tag`.`id`)  
WHERE `Tag`.`id` = 137 ) x);"

这应该强制 MySQL 缓存子查询。或者,如果您知道查询将返回少量值,则最好执行两个单独的查询。

【讨论】:

    【解决方案2】:

    如果查看子查询

    SELECT ct.contact_id 
    FROM contacts_tags AS ct
    LEFT JOIN tags AS t ON ct.tag_id = t.id  
    

    然后它不限制 contact_tags:删除LEFT 以获得限制(等连接)。

    改写如下:

    SELECT DISTINCT c.*
    FROM contacts AS c
    JOIN tags AS t ON  c.id = t.contact_id
    JOIN contacts_tags AS ct ON ct.tag_id = t.id
    WHERE
        t.id = 137
    

    SELECT c.*
    FROM contacts AS c
    JOIN tags AS t ON  c.id = t.contact_id
    WHERE
        t.id = 137
    AND
        EXISTS(SELECT *
        FROM contacts_tags AS ct
        WHERE ct.tag_id = 137)
    

    这很奇怪。似乎缺少某些条件。

    【讨论】:

      猜你喜欢
      • 2018-04-02
      • 2017-03-16
      • 1970-01-01
      • 2012-01-12
      • 1970-01-01
      • 1970-01-01
      • 2021-05-06
      • 1970-01-01
      • 2010-11-24
      相关资源
      最近更新 更多