#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(*)
значение.
Итак, вы хотите, чтобы это было «быстро» или вы хотите, чтобы это было «правильно»?