Когда использовать прямое соединение с MySQL
У меня просто был довольно сложный запрос, с которым я работал, и для запуска потребовалось 8 секунд. EXPLAIN показывал странный порядок таблиц, и мои индексы не все использовались даже с подсказкой индекса силы. Я наткнулся на ключевое слово STRAIGHT_JOIN join и начал заменять им некоторые из моих внутренних ключевых слов JOIN. Я заметил значительное улучшение скорости. В конце концов я просто заменил все мои внутренние ключевые слова JOIN на STRAIGHT_JOIN для этого запроса, и теперь он запускается .Ноль один считанные секунды.
мой вопрос: когда вы используете STRAIGHT_JOIN и когда вы используете INNER JOIN? Есть ли причина не использовать STRAIGHT_JOIN, если вы пишете хорошие запросы?
9 ответов:
Я бы не рекомендовал использовать STRAIGHT_JOIN без уважительной причины. Мой собственный опыт заключается в том, что оптимизатор запросов MySQL выбирает плохой план запроса чаще, чем мне хотелось бы, но недостаточно часто, чтобы вы просто обходили его в целом, что вы и делали бы, если бы всегда использовали STRAIGHT_JOIN.
моя рекомендация-оставить все запросы как обычные соединения. Если вы обнаружите, что один запрос использует неоптимальный план запроса, я бы предложил сначала попытаться переписать или измените структуру запроса немного, чтобы увидеть, будет ли оптимизатор затем выбрать лучший план запроса. Кроме того, для innodb по крайней мере, убедитесь, что это не просто статистика индекса устарела ( АНАЛИЗ ТАБЛИЦЫ). Это может привести к тому, что оптимизатор выберет плохой план запроса. Оптимизатор подсказки, как правило, должны быть вашим последним средством.
еще одна причина не использовать подсказки запроса заключается в том, что ваше распределение данных может измениться с течением времени, или ваша избирательность индекса может измениться и т. д. как ваша таблица растет. Ваши подсказки запроса, которые являются оптимальными сейчас, могут стать неоптимальными с течением времени. Но оптимизатор не сможет адаптировать план запроса из-за своего устаревшего подсказки. Вы остаетесь более гибким, если позволяете оптимизатору принимать решения.
"STRAIGHT_JOIN похож на JOIN, за исключением того, что левая таблица всегда читается перед правой таблицей. Это может быть использовано для тех (немногих) случаев, для которых оптимизатор соединения помещает таблицы в неправильном порядке."
MySQL не обязательно хорош в выборе порядка соединения в сложных запросах. Указав сложный запрос в виде straight_join, запрос выполняет соединения в указанном порядке. Поместив таблицу в первый наименьший общий знаменатель и указав straight_join, вы сможете повысить производительность запроса.
STRAIGHT_JOIN, используя это предложение, вы можете управлятьJOINпорядок: какая таблица сканируется во внешнем цикле, а какая-во внутреннем цикле.
вот сценарий, который появился совсем недавно на работе.
рассмотрим три таблицы, A, B, C.
а имеет 3000 строк; Б 300,000,000 строк; и C и 2000 строк.
внешние ключи определены: B(a_id), B (c_id).
предположим, что у вас есть запрос, который выглядит следующим образом:
select a.id, c.id from a join b on b.a_id = a.id join c on c.id = b.c_idпо моему опыту, MySQL может выбрать, чтобы пойти C - > B - > A в этом случае. C меньше, чем A, А B огромен, и все они равнозначны.
в беда в MySQL не обязательно учитывать площадь пересечения (С. ID и Б. основные достижения и итоговые документы) против (ИД А. и Б. распределения a_id). Если соединение между B и C возвращает столько же строк, сколько и B, то это очень плохой выбор; если бы начиная с A отфильтровывалось B до такого количества строк, как A, то это был бы гораздо лучший выбор.
Как правило, вы хотите сделать ваши соединения в порядке, который минимизирует количество строк в результирующем наборе. Итак, начнем с небольшого стола и соединение таким образом, что результирующее соединение также будет небольшим, идеально. Вещи идут грушевидной формы, если, начиная с небольшого стола и соединяя его с большим столом заканчивается так же, как большой стол.
Это зависит от статистики, хотя. Если распределение данных изменяется, расчет может измениться. Это также зависит от деталей реализации механизма соединения.
Я скажу вам, почему я должен был использовать STRAIGHT_JOIN:
- Я производительность проблема с запросом.
- упрощая запрос, запрос был неожиданно более эффективным
- пытаясь выяснить, какая конкретная часть приносила проблему, я просто не мог. (2 левых соединения были медленными, и каждый из них был независимо быстрым)
- затем я выполнил объяснение с медленным и быстрым запросом (addind один из левых присоединяется)
- Удивительно, но MySQL полностью изменил порядок соединения между двумя запросами.
поэтому я заставил одно из соединений быть straight_join, чтобы заставить предыдущее соединение быть прочитанным первым. Это помешало MySQL изменить порядок выполнения и работало как шарм !
по моему короткому опыту, одна из ситуаций, которые
STRAIGHT_JOINуменьшил мой запрос с 30 секунд до 100 миллисекунд заключается в том, что первая таблица в плане выполнения не была таблицей, которая имеет порядок по столбцам-- table sales (45000000) rows -- table stores (3) rows SELECT whatever FROM sales INNER JOIN stores ON sales.storeId = stores.id ORDER BY sales.date, sales.id LIMIT 50; -- there is an index on (date, id)если оптимизатор выбирает нажмите
storesпервый это вызоветUsing index; Using temporary; Using filesort, потому чтоесли ORDER BY или GROUP BY содержит столбцы из других таблиц первая таблица в очереди соединения-это временная таблица создан.
здесь оптимизатор нуждается в небольшой помощи, сказав ему ударить
salesсначала с помощьюsales STRAIGHT_JOIN stores
если ваш запрос заканчивается
ORDER BY... LIMIT..., это мая оптимально переформулировать запрос, чтобы обмануть оптимизатор в выполненииLIMITдо theJOIN.(этот ответ не относится только к исходному вопросу о
STRAIGHT_JOIN, и это не относится ко всем случаямSTRAIGHT_JOIN.)начиная с пример @Accountantم, это должно работать быстрее в большинстве ситуаций. (И это позволяет избежать необходимости полунамеки.)
SELECT whatever FROM ( SELECT id FROM sales ORDER BY date, id LIMIT 50 ) AS x JOIN sales ON sales.id = x.id JOIN stores ON sales.storeId = stores.id ORDER BY sales.date, sales.id;Примечания:
- во-первых, 50 идентификаторов извлекаются. Это будет особенно быстро с
INDEX(date, id).- затем присоединиться обратно к
salesпозволяет получить только 30 "whatevers"без тащить их вокруг в таблице temp.- поскольку подзапрос, по определению, неупорядочен, то
ORDER BYнеобходимо повторить.- Да, это Мессье. Но это обычно быстрее.
Я против использования хиты, потому что " даже если это быстрее сегодня, это может не быть быстрее завтра."
--use 120s, 18 million data explain SELECT DISTINCT d.taid FROM tvassist_recommend_list_everyday_diverse d, tvassist_taid_all t WHERE d.taid = t.taid AND t.client_version >= '21004007' AND t.utdid IS NOT NULL AND d.recommend_day = '20170403' LIMIT 0, 10000 --use 3.6s repalce by straight join explain SELECT DISTINCT d.taid FROM tvassist_recommend_list_everyday_diverse d STRAIGHT_JOIN tvassist_taid_all t on d.taid = t.taid WHERE t.client_version >= '21004007' AND d.recommend_day = '20170403' AND t.utdid IS NOT NULL LIMIT 0, 10000
Comments