2010-10-21 4 views
3

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

запрос выглядит следующим образом:

SELECT 
    COUNT(*) 
FROM 
    `poems` 
WHERE `id` IN ( 
        SELECT `poem_id` 
        FROM `poems_genres` 
        WHERE `genre_title` = 'derision' 
      ) 
     AND `status` = 'finished'; 

занимает слишком много времени (около 6-10 секунд), так как он не может использовать индексы (из-IN() я думаю?). Есть ли способ переписать этот запрос по-другому, чтобы получить тот же результат быстрее?

ответ

11

MySQL has a problem с in, где он повторно переоценивает некоррелированные подзапросы, как если бы они были коррелированы. Является ли переписывание как соединение улучшающим?

SELECT 
    COUNT(distinct p.`id`) 
FROM `poems` p 
JOIN `poems_genres` pg 
ON p.`id` = pg.`poem_id` 
WHERE pg.`genre_title` = 'derision' AND p.`status` = 'finished'; 

Если нет, то в соответствии с this article (смотрите раздел «Как заставить внутренний запрос, чтобы выполнить первый»), окружив его в производной таблице может помочь.

SELECT 
    COUNT(*) 
FROM 
    `poems` 
WHERE `id` IN 
(
select `poem_id` from (SELECT `poem_id` 
        FROM `poems_genres` 
        WHERE `genre_title` = 'derision') x 

) AND `status` = 'finished'; 
+0

Спасибо, много новой информации для меня :) –

+0

Повторный запрос с использованием JOIN сокращенных строк, рассмотренных по запросу от 4266806 до 1644. Работает как молния :) –

1

Вы также могли бы использовать EXISTS положение и коррелируют на Ид и poem_id полей

SELECT 
    COUNT(*) 
FROM 
    `poems` p1 
WHERE EXISTS 
(
SELECT `poem_id` 
        FROM `poems_genres` pg 
        WHERE `genre_title` = 'derision' and p1.id = pg.poem_id 

) AND `status` = 'finished'; 

Разница между этой и он будет пытаться использовать индексы вместо делать полное сканирование таблицы.

Смежные вопросы