Подзапросы против объединений - PullRequest
155 голосов
/ 26 сентября 2008

Я рефакторил медленный раздел приложения, которое мы унаследовали от другой компании, чтобы использовать внутреннее соединение вместо подзапроса, подобного

where id in (select id from ... )

Реорганизованный запрос выполняется примерно в 100 раз быстрее. (от ~ 50 секунд до ~ 0,3) Я ожидал улучшения, но кто-нибудь может объяснить, почему он был таким радикальным? Все столбцы, использованные в предложении where, были проиндексированы. SQL выполняет запрос в предложении where один раз за строку или что-то в этом роде?

Обновление - Объяснить результаты:

Разница во второй части запроса "where id in ()" -

2   DEPENDENT SUBQUERY  submission_tags ref st_tag_id   st_tag_id   4   const   2966    Using where

против 1 индексированной строки с объединением:

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index

Ответы [ 14 ]

155 голосов
/ 26 сентября 2008

«Коррелированный подзапрос» (то есть тот, в котором условие where зависит от значений, полученных из строк содержащего запроса) будет выполняться один раз для каждой строки. Некоррелированный подзапрос (тот, в котором условие where не зависит от содержащего запроса) будет выполняться один раз в начале. Механизм SQL делает это различие автоматически.

Но, да, план объяснения даст вам грязные детали.

36 голосов
/ 26 сентября 2008

Вы запускаете подзапрос один раз для каждой строки , тогда как объединение происходит по индексам.

16 голосов
/ 28 сентября 2008

Вот пример того, как подзапросы оцениваются в MySQL 6.0 .

Новый оптимизатор преобразует этот тип подзапросов в объединения.

7 голосов
/ 26 сентября 2008

Запустите объяснительный план для каждой версии, он скажет вам, почему.

6 голосов
/ 26 сентября 2008

перед выполнением запросов к набору данных, которые они передают через оптимизатор запросов, оптимизатор пытается организовать запрос таким образом, чтобы он мог удалить как можно больше кортежей (строк) из набора результатов. Часто, когда вы используете подзапросы (особенно плохие), кортежи не могут быть удалены из результирующего набора, пока внешний запрос не начнет выполняться.

Без просмотра запроса трудно сказать, что было плохого в оригинале, но я думаю, что это было то, что оптимизатор просто не мог сделать намного лучше. Запуск объяснения покажет вам метод оптимизаторов для извлечения данных.

4 голосов
/ 26 сентября 2008

Подзапрос where должен выполнить 1 запрос для каждой возвращаемой строки. Внутреннее объединение просто должно выполнить 1 запрос.

4 голосов
/ 26 сентября 2008

Этот вопрос несколько общий, поэтому вот общий ответ:

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

Сделайте это:

Запустите EXPLAIN для каждого из запросов (один из них - JOIN, а затем - для подзапроса) и опубликуйте результаты здесь.

Я думаю, что различие в интерпретации этих запросов MySQL будет полезным для всех.

4 голосов
/ 26 сентября 2008

Обычно это результат того, что оптимизатор не может выяснить, что подзапрос может быть выполнен как объединение, и в этом случае он выполняет подзапрос для каждой записи в таблице, а не присоединяет таблицу в подзапросе к таблице, которую вы запрашивают. Некоторые из более «корпоративных» баз данных лучше справляются с этой задачей, но они все еще иногда упускают ее.

3 голосов
/ 26 сентября 2008

Подзапрос, вероятно, выполнял "полное сканирование таблицы". Другими словами, не используя индекс и возвращая слишком много строк, которые необходимо было отфильтровать из основного запроса.

Просто предположение без подробностей, конечно, но это обычная ситуация.

3 голосов
/ 26 сентября 2008

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

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