Вот сценарий, который недавно возник на работе.
Рассмотрим три таблицы: A, B, C.
A имеет 3000 строк; B имеет 300000000 строк; а в 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 не обязательно учитывает размер пересечения между (C.id и B.c_id) и (A.id и B.a_id). Если соединение между B и C возвращает столько же строк, сколько B, то это очень плохой выбор; если бы, начиная с A, отфильтровал бы B до такого количества строк, как A, то это был бы гораздо лучший выбор. straight_join
можно использовать для принудительного выполнения этого порядка следующим образом:
select a.id, c.id
from a
straight_join b on b.a_id = a.id
join c on c.id = b.c_id
Теперь a
нужно присоединиться к предыдущему b
.
Обычно вы хотите выполнять соединения в порядке, который минимизирует количество строк в результирующем наборе. Итак, начать с небольшой таблицы и объединить так, чтобы результирующее соединение также было небольшим, идеально. Все становится грушевидным, если, начиная с маленького стола, и присоединяя его к большему, получается таким же большим, как и большой стол.
Хотя это зависит от статистики. Если распределение данных изменится, расчет может измениться. Это также зависит от деталей реализации механизма соединения.
Худшие случаи, которые я видел для MySQL, когда все, кроме обязательного straight_join
или агрессивного хинтинга индекса, - это запросы, которые разбивают на страницы множество данных в строгом порядке сортировки с легкой фильтрацией. MySQL настоятельно предпочитает использовать индексы для любых фильтров и объединений вместо сортировок; это имеет смысл, потому что большинство людей не пытаются отсортировать всю базу данных, а имеют ограниченное подмножество строк, которые реагируют на запрос, а сортировка ограниченного подмножества происходит намного быстрее, чем фильтрация всей таблицы, независимо от того, отсортирована она или не. В этом случае, помещая прямое соединение сразу после таблицы, в которой был индексированный столбец, я хотел отсортировать фиксированные элементы.
straight_join
.