Вложенный SQL-запрос занимает слишком много времени - PullRequest
3 голосов
/ 21 октября 2010

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

Запрос выглядит так:

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

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

Ответы [ 2 ]

11 голосов
/ 21 октября 2010

MySQL имеет проблему с 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';

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

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';
1 голос
/ 21 октября 2010

Вы также можете использовать предложение EXISTS и сопоставлять поля id и 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';

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

...