Правое соединение MySQL на порядок быстрее для подсчета

#mysql #sql #query-performance #outer-join

#mysql #sql #запрос-производительность #внешнее соединение

Вопрос:

Имея две таблицы products , submissions обе с примерно 1 миллионом записей и полностью проиндексированные, я хочу подсчитать элементы на основе условия. Однако даже подсчет базового результата соединения происходит очень медленно.

Таблицы имеют отношение 1-1 с submissions наличием product_id внешнего ключа. Смотрите Следующие 4 запроса:

 select count(*)
from products P 
join submissions S on S.product_id=P.id 
# Takes 2 seconds
  

И объясните этот запрос:

 1   SIMPLE  S   index   submissions_product_id_foreign  submissions_product_id_foreign  4   NULL    776660  Using index
1   SIMPLE  P   eq_ref  PRIMARY PRIMARY 4   ma_prod.S.product_id    1   Using index
  

Однако выполнение следующего запроса:

 select count(*)
from products P 
RIGHT join submissions S on S.product_id=P.id 
  

Занимает 300 мс. Объяснение также отличается:

 1   SIMPLE  S   index   NULL    submissions_product_id_foreign  4   NULL    776662  Using index
  

Я не могу понять, что происходит. Оба запроса имеют одинаковый результат и выполняют одно и то же соединение, так почему же одна из них пропускает eq_ref операцию? Кроме того, eq_ref предполагается, что он должен быть очень быстрым для внешнего ключа.

Комментарии:

1. Обратите внимание, что никто никогда не использует RIGHT JOIN

2. Я просто пытаюсь понять, что происходит. Вы можете поменять местами таблицы и вместо этого использовать ЛЕВОЕ СОЕДИНЕНИЕ, те же результаты.

3. Хороший план. :-).

4. Отличаются ли результаты? Если это так, вы не можете использовать одну формулировку вместо другой.

5. Правые внешние соединения встречаются реже, но было бы преувеличением сказать, что они никогда не используются. См quora.com /…

Ответ №1:

Документация MySQL JOIN довольно плотная, но в ней говорится об одной забавной вещи:

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

И для вашего запроса RIGHT JOIN убеждает оптимизатора прочитать правую таблицу перед левой таблицей, что лучше. Возьмите каждую отправку и найдите один продукт, с которым она идет, используя первичный ключ — vs возьмите каждый продукт и найдите несколько отправлений, которые идут с ним, даже используя индекс. Последний подход, очевидно, повторяет таблицу больше раз.

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

Ответ №2:

RIGHT и LEFT JOINs скажите, что наличие одной из таблиц (левой или правой соответственно) необязательно.

Обычно используется left или right, когда вам нужны NULLs недостающие данные или для обнаружения недостающих строк. Но вы не делаете ни того, ни другого.

Вы спрашиваете, сколько существует отправлений, и на самом деле не заботитесь о том, есть ли совпадение product . И оптимизатор понял, что product это бесполезно, и выбросил его при разработке выполнения запроса.

Итак, это быстрее. Но, вероятно, имеет другое COUNT(*) значение.

Итак, вы хотите, чтобы это было «быстро» или вы хотите, чтобы это было «правильно»?