Вы можете предварять свои запросы с EXPLAIN
, чтобы узнать, как MySQL будет использовать индексы и в каком порядке он присоединится к таблицам.
Взгляните на документацию EXPLAIN
output format, чтобы узнать, как интерпретировать результат.
Из-за LEFT JOIN
s порядок таблиц не может быть изменен. MySQL должен включать в конечный результат все строки из левой таблицы, независимо от того, имеют ли они соответствия в правой таблице.
В INNER JOIN
s MySQL обычно меняет местами таблицы и ставит таблицу с меньшим количеством строк, потому что таким образом она имеет меньшее количество строк для анализа.
Давайте возьмем этот запрос (это ваш запрос с более короткими именами для таблиц):
SELECT *
FROM a
LEFT JOIN b ON a.col = b.col
WHERE 1
Как MySQL работает этот запрос:
Он получает первую строку из таблицы a
, что соответствует условия запроса. Если существуют условия в WHERE
или в статьях join, которые используют только поля таблицы a
и константные значения, то индекс, содержащий некоторые или все эти поля, используется для фильтрации только строк, соответствующих условиям.
После того, как строка из таблицы a
была выбрана, она переходит к следующей таблице из плана выполнения (в нашем запросе это таблица b
). Он должен выбрать все строки, которые соответствуют условиям (состояниям) WHERE
и условиям (0) JOIN
. Более конкретно, строки (строки), выбранные из таблицы b
, должны соответствовать условию b.col = X
, где X
- значение столбца col
для строки, выбранной в настоящее время из таблицы a
на шаге 1. Она находит, что первая соответствующая строка затем переходит к следующей таблице. Поскольку в этом запросе нет «следующей таблицы», она помещает пару строк (от и b
) в результирующий набор, затем отбрасывает строку от b
и ищет следующую, повторяя этот шаг, пока не найдет все строки от b
, которые соответствуют строке, выбранной в настоящий момент от a
(на шаге 1).
Если на шаг-не может найти любую строку из b
, которые соответствуют строке в данный момент, выбранную из a
, то LEFT JOIN
силы MySQL, чтобы составить строку (имеющие столбцы b
) полный NULL
с и вместе с текущей строкой от a
он создает строку, помещающую ее в результирующий набор.
После того, как были обработаны все совпадающие строки из b
, MySQL отбрасывает текущая строка из a
, выбирает следующую строку из a
, который соответствует WHERE
и вступать в условия и начинает более с выбором соответствующих строк из b
(шаг 2).
Этот процесс обрабатывается до тех пор, пока не будут обработаны все строки из a
.
Примечания:
Значение "первой строки" на шаге 1, зависит от многих факторов. Например, если есть индекс в таблице a
, который содержит все столбцы (из таблицы a
), указанные в запросе, тогда MySQL не будет читать данные таблицы, но вместо этого будет использовать индекс. В этом случае порядок строк задается индексом. В других случаях строки считываются из данных таблицы, а порядок предоставляется по порядку, который они хранят на носителе.
Этот простой запрос не имеет никакого WHERE
условия (WHERE 1
всегда TRUE), а также нет никаких условий в пункте JOIN
, который содержит только столбцы из a
. Все строки из таблицы a
включены в результирующий набор, что приводит к full table scan или, если это возможно, сканированию индекса.
На шаге 2, если таблица b
имеет индекс по столбцу col
затем MySQL использует индекс, чтобы найти строки из b
, которые имеют значение X
на колонке col
. Это быстрая операция. Если таблица b
не указана в столбце col
, тогда MySQL должен выполнить full table scan
таблицы b
. Это означает, что он должен читать все строки таблицы b
, чтобы найти тех, которые имеют значения X
на колонке col
. Это очень медленная и ресурсоемкая операция.
Поскольку нет условий для строк таблицы a
, MySQL не может использовать индекс таблицы a
для фильтрации выбранных строк. С другой стороны, когда ему нужно выбрать строки из таблицы b
(на шаге 2), у него есть условие для соответствия (b.col = X
), и он может использовать индекс для ускорения выбора, поскольку такой индекс существует в таблице b
,
Это объясняет большую разницу в производительности между двумя вашими запросами. Более того, из-за LEFT JOIN
ваши два запроса не эквивалентны, они дают разные результаты.
Отказ от ответственности: Обратите внимание, что приведенный выше перечень шагов является чрезмерно упрощенным объяснением того, как работает выполнение запроса. Он пытается выразить это простыми словами и пропустить многие технические аспекты того, что происходит за сценой.
Советы о том, как сделать свой бег запросов быстрее можно найти в документации MySQL, раздел 8. Optimization
Нет разницы. Оптимизатор должен выбрать самый быстрый способ выполнить запрос, независимо от того, каким образом вы укажете условие соединения. – jarlh
Вы выбираете все строки из таблицы, чтобы индексированная таблица была быстрее. Это не имеет значения, если это был INNER JOIN. – Mihai
@jarlh Нет никакой разницы в 'INNER JOIN's. В 'LEFT JOIN' оптимизатор не может менять таблицы. – axiac