Ось сценарій, який нещодавно з’явився на роботі.
Розглянемо три таблиці, A, B, C.
А має 3000 рядків; B має 300 000 000 рядків; а С має 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
.