Подзапросы против присоединится
Я рефакторингу медленный раздела аппликации, который мы унаследовали от другой компании, чтобы использовать внутреннее соединение вместо подзапроса как
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
vs 1 индексированная строка с соединением:
SIMPLE s eq_ref PRIMARY PRIMARY 4 newsladder_production.st.submission_id 1 Using index
14 ответов:
"коррелированный подзапрос" (т. е. тот, в котором условие where зависит от значений, полученных из строк содержащего запроса) будет выполняться один раз для каждой строки. Некоррелированный подзапрос (тот, в котором условие where не зависит от содержащего запроса) будет выполняться один раз в начале. Механизм SQL делает это различие автоматически.
Но, да, объясните-план даст вам грязные детали.
вот пример подзапросы оцениваются в MySQL 6.0.
новый оптимизатор преобразует этот вид подзапросов в соединения.
перед выполнением запросов к набору данных они помещаются через оптимизатор запросов, оптимизатор пытается организовать запрос таким образом, чтобы он мог удалить как можно больше кортежей (строк) из результирующего набора так быстро, как это возможно. Часто при использовании подзапросов (особенно плохих) кортежи не могут быть вырезаны из результирующего набора, пока внешний запрос не начнет выполняться.
без просмотра запроса трудно сказать, что было так плохо в оригинале, но мое предположение было бы это то, что оптимизатор просто не мог сделать намного лучше. Запуск 'explain' покажет вам метод оптимизаторов для получения данных.
обычно это результат того, что оптимизатор не может понять, что подзапрос может быть выполнен как соединение, и в этом случае он выполняет подзапрос для каждой записи в таблице, а не присоединяет таблицу в подзапросе к таблице, которую вы запрашиваете. Некоторые из более" предприимчивых " баз данных лучше в этом, но они все еще пропускают его иногда.
этот вопрос несколько общий, поэтому вот общий ответ:
в основном, запросы занимают больше времени, когда MySQL имеет тонны строк для сортировки.
этого:
запустите объяснение для каждого из запросов (объединенный, затем вложенный) и опубликуйте результаты здесь.
Я думаю, что видеть разницу в интерпретации MySQL этих запросов будет опыт обучения для всех.
подзапрос where должен выполнить 1 запрос для каждой возвращенной строки. Внутреннее соединение просто должно выполнить 1 запрос.
посмотреть план запроса для каждого запроса.
, где в и вступить можете обычно быть реализованы с использованием того же плана выполнения, так что обычно существует нулевое ускорение от изменения между ними.
оптимизатор не сделал очень хорошую работу. Обычно они могут быть преобразованы без каких-либо различий, и оптимизатор может это сделать.
подзапрос, вероятно, выполнял "полное сканирование таблицы". Другими словами, не используя индекс и возвращая слишком много строк, которые нужно было отфильтровать из основного запроса.
просто догадка без деталей, конечно, но это обычная ситуация.
с подзапросом вы должны повторно выполнить 2-й выбор для каждого результата, и каждое выполнение обычно возвращает 1 строку.
при соединении 2-й SELECT возвращает намного больше строк, но вам нужно выполнить его только один раз. Преимущество заключается в том, что теперь вы можете присоединиться к результатам, а отношения присоединения-это то, что база данных должна быть хороша. Например, оптимизатор может определить, как лучше использовать индекс сейчас.
Это не столько подзапрос, сколько предложение IN, хотя соединения лежат в основе, по крайней мере, SQL-движка Oracle и выполняются чрезвычайно быстро.
взято из справочного руководства (14.2.10.11 переписывание подзапросов как соединений):
левое [внешнее] соединение может быть быстрее, чем эквивалентный подзапрос, потому что сервер может быть в состоянии оптимизировать его лучше-факт, который не является специфичным только для сервера MySQL.
поэтому подзапросы могут быть медленнее, чем левые [внешние] соединения.
Comments