Mysql Sub-Select Проблема - PullRequest
       15

Mysql Sub-Select Проблема

1 голос
/ 29 июля 2009

У меня есть два запроса, чтобы получить связанные теги из базы данных MySQL, один работает, другой нет, мой вопрос: «почему?»

Проблема: При выполнении первого запроса сервер mysql получает 100% загрузки процессора и должен быть перезапущен, чтобы снова работать.

Запрос 1 (не работает):

SELECT tags.*, COUNT(ct.company_id) AS count
FROM company2tag ct, tags
WHERE ct.company_id IN (
    SELECT ct.company_id FROM company2tag ct
    WHERE ct.tag_id = 18
    GROUP BY ct.company_id
    HAVING COUNT(ct.company_id) = 1
)
AND tags.id != 18
AND tags.id = ct.tag_id
GROUP BY ct.tag_id
ORDER BY count DESC
LIMIT 5;

Запрос 2 (работает):

SELECT tags.*, COUNT(ct.company_id) AS count
FROM company2tag ct, tags
WHERE ct.company_id IN (5864, 5870, 6140, 6221, 6268)
    AND tags.id != 18
    AND tags.id = ct.tag_id
GROUP BY ct.tag_id
ORDER BY count DESC
LIMIT 5;

Насколько я понимаю, два вышеупомянутых запроса полностью совпадают, единственное отличие состоит в том, что первый запрос извлекает свои "company_id" с помощью подвыбора.

Как это может произойти?

Ответы [ 2 ]

3 голосов
/ 29 июля 2009

Прежде всего, у вас могут возникнуть проблемы с первым запросом, поскольку у вас есть две таблицы с псевдонимами ct ... одна во внешнем запросе, другая во вложенном запросе.

Во-вторых, вы можете переписать IN как JOIN:

SELECT tags.*, COUNT(ct.company_id) AS count
FROM company2tag ct
INNER JOIN tags ON tags.id = ct.tag_id
INNER JOIN (
    SELECT company_id FROM company2tag
    WHERE tag_id = 18
    GROUP BY company_id
    HAVING COUNT(company_id) = 1
) ctf ON ct.company_id = ctf.company_id
WHERE tags.id != 18
GROUP BY ct.tag_id
ORDER BY count DESC
LIMIT 5;

Обратите внимание, что я на самом деле не проверял это.

2 голосов
/ 29 июля 2009

MySQL не очень хорош в оптимизации IN условий.

Условие в вашем первом запросе не может быть легко переписано как EXISTS, поэтому MySQL проверяет результаты для каждой строки.

Если вы хотите выбрать company_id, которые упоминаются более одного раза в tag 18, лучше переписать этот запрос следующим образом:

SELECT  tags.*, COUNT(company_id) AS count
FROM    company2tag ct
JOIN    tags
ON      tags.id = ct.tag_id
WHERE   ct.tag_id <> 18
        AND NOT EXISTS
        (
        SELECT  NULL
        FROM    company2tag cti
        WHERE   cti.tag_id = 18
                AND cti.company_id = ct.company_id
        LIMIT 1, 1
        )
GROUP BY
        ct.tag_id
ORDER BY
        count DESC

Основная идея здесь заключается в том, что вам не нужно COUNT(*): достаточно просто проверить, что существуют хотя бы два значения.

См. Эту статью в моем блоге для аналогичной проблемы:

Имея следующий индекс:

CREATE INDEX ix_company2tag_tag_company_id ON company2tag (tag_id, company_id)

значительно улучшит этот запрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...