Использование MySQL "в" вызывает цикл? - PullRequest
1 голос
/ 06 февраля 2012

Когда я изолирую этот запрос:

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

В чем разница?

Ответы [ 2 ]

1 голос
/ 06 февраля 2012

Текущий выпуск MySQL от GA действительно плох в оптимизации подзапросов.Скорее всего, подзапрос выполняется для каждой строки в Contacts.Вы можете увидеть это, если вы запустите EXPLAIN your_query_here.Вы увидите, что подзапрос был помечен DEPENDENT SUBQUERY.

Это не очень хорошее решение, но что-то вроде этого может работать.подзапрос.В качестве альтернативы, если вы знаете, что запрос будет возвращать небольшое количество значений, вам может быть лучше просто выполнить два отдельных запроса.

0 голосов
/ 06 февраля 2012

Если посмотреть на подзапрос

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)

Что странно. Похоже, что какое-то условие отсутствует.

...