2015-02-17 3 views
0

У меня есть 2 таблицы с общим полем. На одной таблице общее поле имеет индекс , а с другой нет. Выполнение запроса в следующем виде:Использование индекса Mysql

SELECT * 
FROM table_with_index 
LEFT JOIN table_without_index ON table_with_index.comcol = table_without_index.comcol 
WHERE 1 

запрос будет гораздо меньше, чем исполнительская работает наоборот:

SELECT * 
FROM table_without_index 
LEFT JOIN table_with_indexON table_without_index.comcol = table_with_index.comcol 
WHERE 1 

Кто-нибудь может объяснить мне, почему и логику использования индексов в этом случае?

+2

Нет разницы. Оптимизатор должен выбрать самый быстрый способ выполнить запрос, независимо от того, каким образом вы укажете условие соединения. – jarlh

+0

Вы выбираете все строки из таблицы, чтобы индексированная таблица была быстрее. Это не имеет значения, если это был INNER JOIN. – Mihai

+2

@jarlh Нет никакой разницы в 'INNER JOIN's. В 'LEFT JOIN' оптимизатор не может менять таблицы. – axiac

ответ

0

Вы можете предварять свои запросы с 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 работает этот запрос:

  1. Он получает первую строку из таблицы a, что соответствует условия запроса. Если существуют условия в WHERE или в статьях join, которые используют только поля таблицы a и константные значения, то индекс, содержащий некоторые или все эти поля, используется для фильтрации только строк, соответствующих условиям.

  2. После того, как строка из таблицы a была выбрана, она переходит к следующей таблице из плана выполнения (в нашем запросе это таблица b). Он должен выбрать все строки, которые соответствуют условиям (состояниям) WHERE и условиям (0) JOIN. Более конкретно, строки (строки), выбранные из таблицы b, должны соответствовать условию b.col = X, где X - значение столбца col для строки, выбранной в настоящее время из таблицы a на шаге 1. Она находит, что первая соответствующая строка затем переходит к следующей таблице. Поскольку в этом запросе нет «следующей таблицы», она помещает пару строк (от и b) в результирующий набор, затем отбрасывает строку от b и ищет следующую, повторяя этот шаг, пока не найдет все строки от b, которые соответствуют строке, выбранной в настоящий момент от a (на шаге 1).

  3. Если на шаг-не может найти любую строку из b, которые соответствуют строке в данный момент, выбранную из a, то LEFT JOIN силы MySQL, чтобы составить строку (имеющие столбцы b) полный NULL с и вместе с текущей строкой от a он создает строку, помещающую ее в результирующий набор.

  4. После того, как были обработаны все совпадающие строки из b, MySQL отбрасывает текущая строка из a, выбирает следующую строку из a, который соответствует WHERE и вступать в условия и начинает более с выбором соответствующих строк из b (шаг 2).

  5. Этот процесс обрабатывается до тех пор, пока не будут обработаны все строки из 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

0

Чтобы проверить, что происходит с оптимизатором MySQL Query, пожалуйста, отобразите план EXPLAIN этих двух запросов. Идет так:

EXPLAIN 
SELECT * FROM table_with_index 
LEFT JOIN table_without_index ON table_with_index.comcol =  table_without_index.comcol 
WHERE 1 

и

EXPLAIN 
SELECT * 
FROM table_without_index 
LEFT JOIN table_with_indexON table_without_index.comcol = table_with_index.comcol 
WHERE 1