Oto scenariusz, który pojawił się niedawno w pracy.
Rozważ trzy tabele, A, B, C.
A ma 3000 wierszy; B ma 300 000 000 wierszy; a C ma 2000 wierszy.
Zdefiniowano klucze obce: B (a_id), B (c_id).
Załóżmy, że masz zapytanie, które wygląda następująco:
select a.id, c.id
from a
join b on b.a_id = a.id
join c on c.id = b.c_id
Z mojego doświadczenia wynika, że MySQL może w tym przypadku wybrać C -> B -> A. C jest mniejsze niż A, a B jest ogromne i wszystkie są równonożne.
Problem polega na tym, że MySQL niekoniecznie bierze pod uwagę rozmiar przecięcia między (C.id i B.c_id) a (A.id i B.a_id). Jeśli sprzężenie między B i C zwraca tyle samo wierszy, co B, to jest to bardzo zły wybór; gdyby zaczynając od A przefiltrował B do tylu wierszy co A, to byłby to znacznie lepszy wybór. straight_join
można użyć do wymuszenia tego zamówienia w następujący sposób:
select a.id, c.id
from a
straight_join b on b.a_id = a.id
join c on c.id = b.c_id
Teraz a
należy dołączyć wcześniej b
.
Ogólnie rzecz biorąc, chcesz wykonywać łączenia w kolejności minimalizującej liczbę wierszy w wynikowym zestawie. Zatem rozpoczęcie od małego stolika i łączenie w taki sposób, aby wynikowe połączenie również było małe, jest idealne. Sprawy przybierają kształt gruszki, jeśli zaczynając od małego stołu i łącząc go z większym stołem, kończy się tak samo, jak duży stół.
Jest to jednak zależne od statystyk. Jeśli zmieni się dystrybucja danych, obliczenia mogą ulec zmianie. Zależy to również od szczegółów implementacji mechanizmu łączenia.
Najgorsze przypadki, jakie widziałem w przypadku MySQL, w których wszystkie oprócz wymaganych straight_join
lub agresywnych podpowiedzi do indeksów, to zapytania, które dzielą się na strony wielu danych w ścisłej kolejności sortowania z lekkim filtrowaniem. MySQL zdecydowanie preferuje używanie indeksów do wszelkich filtrów i łączenia zamiast sortowania; ma to sens, ponieważ większość ludzi nie próbuje sortować całej bazy danych, ale raczej ma ograniczony podzbiór wierszy, które odpowiadają na zapytanie, a sortowanie ograniczonego podzbioru jest znacznie szybsze niż filtrowanie całej tabeli, bez względu na to, czy jest posortowana, czy nie. W tym przypadku, wstawiając proste sprzężenie bezpośrednio po tabeli, która miała zindeksowaną kolumnę, chciałem posortować według ustalonych rzeczy.
straight_join
.