2009-08-07 18 views
5

Próbuję lepiej zrozumieć, dlaczego ta optymalizacja zapytań jest tak ważna (ponad 100 razy szybciej), że mogę ponownie użyć podobnej logiki dla innych zapytań.dlaczego MySQL JOIN jest znacznie szybszy niż WHERE IN (podzapytanie)?

Używanie MySQL 4.1 - RESET QUERY CACHE i TABLICE FLUSH zostały wykonane, zanim wszystkie zapytania i czas zakończenia mogą być odtworzone konsekwentnie. Jedyną rzeczą, która jest dla mnie oczywista na EXPLAIN, jest to, że podczas JOIN trzeba znaleźć tylko 5 wierszy? Ale czy to jest cała odpowiedź na szybkość? Oba pytania są stosujących częściowy indeks (forum_stickies) w celu określenia statusu usuniętych wątków (topic_status = 0)

ekranu do głębszej analizy z EXPLAIN

powolny zapytanie: 0.7+ sekund (cache wyczyszczone)

SELECT SQL_NO_CACHE forum_id, topic_id FROM bb_topics 
WHERE topic_last_post_id IN 
(SELECT SQL_NO_CACHE MAX (topic_last_post_id) AS topic_last_post_id 
FROM bb_topics WHERE topic_status=0 GROUP BY forum_id) 

szybko zapytania: 0.004 sekund lub mniej (cache wyczyszczone)

SELECT SQL_NO_CACHE forum_id, topic_id FROM bb_topics AS s1 
JOIN 
(SELECT SQL_NO_CACHE MAX(topic_last_post_id) AS topic_last_post_id 
FROM bb_topics WHERE topic_status=0 GROUP BY forum_id) AS s2 
ON s1.topic_last_post_id=s2.topic_last_post_id 

Uwaga nie ma indeksu na najważniejszej kolumnie (topic_last_post_id), ale że nie można pomóc (wyniki zapisywane są do wielokrotnego użytku tak).

Czy odpowiedź jest prosta, ponieważ pierwsze zapytanie musi zeskanować topic_last_post_id TWICE, po raz drugi, aby dopasować wyniki do podzapytania? Jeśli tak, dlaczego jest wykładniczo wolniejsza?

(mniej ważne Jestem ciekawy dlaczego pierwsze zapytanie nadal trwa tak długo, gdybym faktycznie umieścić indeksu na topic_last_post_id)

aktualizacji: Znalazłem ten wątek na stackoverflow po wielu poszukiwaniach później na który przechodzi w tym temacie Subqueries vs joins

Odpowiedz

4

Może silnik wykonuje podzapytanie dla każdego wiersza w obszarze bb_topics, aby sprawdzić, czy znajdzie wynik topic_last_post_id w wynikach. Byłoby głupio, ale tłumaczyłoby to ogromną różnicę.

+1

Wow, które mogą być możliwe. Pomyślałem tylko, że może robi zapytanie dla każdego z id w wynikach grupy (5 z nich), ale teraz, gdy o tym wspomniałeś, zastanawiam się, czy robi to dla wszystkich 209 (lub nawet gorszych 293) wierszy. Wysłałem do kogoś prośbę o wypróbowanie zapytań na znacznie większym zbiorze danych (10 000 wierszy względem 300), więc widzę, że problem jest jeszcze bardziej powiększony, co udowodni tę teorię. –

+1

Po prostu zdarzyło mi się również wypróbować to po prostu zapytanie 'WYBIERZ SQL_NO_CACHE ID_for, topic_id Z Bb_topics WHERE topic_last_post_id IN (1516,1567,1572,1569,1578)' i jest bardzo szybki. Więc masz rację, to wykonuje podzapytanie dla każdego wiersza, wow to jest szalone. –

+0

Wydaje się, że zostało to naprawione w wersji 5.6 (nie jest to "ZALEŻNE PODLICZENIE"), a wydajność jest podobna do JOIN. – Vatev

0

Powiedziałabym, że ponieważ argumentem wewnątrz klauzuli IN() może być cokolwiek, w czym się tam znajdujesz, DB musi sprawdzić wszystko, co jest zwracane. Kiedy dołączasz do stołów, stosuje się wiele taktyki zwiększania wydajności, na przykład prawdopodobnie używa indeksów, aby uzyskać przewagę.

Powiązane problemy