Czy zapytania JOIN są szybsze niż kilka zapytań? (Uruchamiasz swoje główne zapytanie, a następnie uruchamiasz wiele innych poleceń SELECT w oparciu o wyniki Twojego głównego zapytania)
Pytam, ponieważ DOŁĄCZENIE ich bardzo skomplikowałoby projekt mojej aplikacji
Jeśli są szybsze, czy ktoś może z grubsza oszacować, o ile? Jeśli jest 1,5x, nie obchodzi mnie to, ale jeśli jest 10x, chyba tak.
mysql
database
join
query-optimization
Thomas Bonini
źródło
źródło
Odpowiedzi:
Jest to zbyt niejasne, aby dać ci odpowiedź odpowiednią dla twojego konkretnego przypadku. To zależy od wielu rzeczy. Pisał o tym Jeff Atwood (założyciel tej strony) . Jednak w przeważającej części, jeśli masz odpowiednie indeksy i poprawnie wykonujesz JOIN, zwykle będzie to szybsze wykonanie 1 podróży niż kilku.
źródło
W przypadku sprzężeń wewnętrznych jedno zapytanie ma sens, ponieważ otrzymujesz tylko pasujące wiersze. W przypadku złączeń lewostronnych wiele zapytań jest znacznie lepszych ... spójrz na następujący test porównawczy, który zrobiłem:
Pojedyncze zapytanie z 5 połączeniami
pytanie: 8,074508 sekund
wielkość wyniku: 2268000
5 zapytań z rzędu
połączony czas zapytania: 0,00262 sekundy
wielkość wyniku: 165 (6 + 50 + 7 + 12 + 90)
.
Zauważ, że otrzymujemy te same wyniki w obu przypadkach (6 x 50 x 7 x 12 x 90 = 2268000)
lewe sprzężenia zajmują wykładniczo więcej pamięci z nadmiarowymi danymi.
Limit pamięci może nie być tak zły, jeśli łączysz tylko dwie tabele, ale generalnie trzy lub więcej i staje się to warte różnych zapytań.
Na marginesie, mój serwer MySQL znajduje się tuż obok mojego serwera aplikacji ... więc czas połączenia jest znikomy. Jeśli czas połączenia jest w sekundach, być może jest to korzystne
Szczery
źródło
To pytanie jest stare, ale brakuje niektórych testów. Porównałem JOIN z jego 2 konkurentami:
WHERE IN(...)
lub odpowiednikaWynik jest jasny: na MySQL
JOIN
jest znacznie szybszy. Zapytania N + 1 mogą drastycznie obniżyć wydajność aplikacji:To znaczy, chyba że wybierzesz wiele rekordów, które wskazują na bardzo małą liczbę odrębnych, zagranicznych rekordów. Oto punkt odniesienia dla skrajnego przypadku:
Jest to bardzo mało prawdopodobne w typowej aplikacji, chyba że łączysz się z relacją -to-many, w którym to przypadku klucz obcy znajduje się w drugiej tabeli i wielokrotnie kopiujesz dane z tabeli głównej.
Na wynos:
JOIN
Zobacz mój artykuł na Medium, aby uzyskać więcej informacji.
źródło
Właściwie to sam doszedłem do tego pytania szukając odpowiedzi, a po przeczytaniu udzielonych odpowiedzi mogę się tylko zgodzić, że najlepszym sposobem porównania wydajności zapytań DB jest uzyskanie rzeczywistych liczb, ponieważ jest zbyt wiele zmiennych do wzięcia pod uwagę ALE myślę również, że porównywanie liczb między nimi prowadzi do niczego dobrego w prawie wszystkich przypadkach. Chodzi mi o to, że liczby należy zawsze porównywać z dopuszczalną liczbą i zdecydowanie nie porównywać między sobą.
Rozumiem, że jeśli jeden sposób odpytywania zajmuje powiedzmy 0,02 sekundy, a drugi 20 sekund, to ogromna różnica. Ale co, jeśli jeden sposób wykonywania zapytań zajmuje 0,0000000002 sekundy, a drugi 0,0000002 sekundy? W obu przypadkach jedna droga jest aż 1000 razy szybsza niż druga, ale czy rzeczywiście wciąż „fest” w drugim przypadku?
Podsumowując, jak osobiście to widzę: jeśli działa dobrze, wybierz proste rozwiązanie.
źródło
Wykonałem szybki test, wybierając jeden wiersz z tabeli zawierającej 50 000 wierszy i łącząc go z jednym wierszem z tabeli zawierającej 100 000 wierszy. Zasadniczo wyglądał tak:
vs
Dwie metody wyboru zajęły 3,7 sekundy dla 50000 odczytów, podczas gdy JOIN zajęło 2,0 sekundy na moim wolnym komputerze w domu. INNER JOIN i LEFT JOIN nie robiły różnicy. Pobieranie wielu wierszy (np. Przy użyciu IN SET) dało podobne wyniki.
źródło
Prawdziwe pytanie brzmi: czy te rekordy mają relację jeden do jednego czy jeden do wielu ?
Odpowiedź TLDR:
Jeśli masz jeden do jednego, użyj pliku
JOIN
instrukcji.Jeśli jeden do wielu, użyj jednej (lub wielu)
SELECT
instrukcji z optymalizacją kodu po stronie serwera.Dlaczego i jak używać SELECT do optymalizacji
SELECT
Praca (z wieloma zapytaniami zamiast łączenia) na dużej grupie rekordów w oparciu o relację jeden do wielu zapewnia optymalną wydajność, ponieważJOIN
wiąże się z wykładniczym problemem wycieku pamięci. Pobierz wszystkie dane, a następnie posortuj je za pomocą języka skryptowego po stronie serwera:Wyniki:
Tutaj otrzymuję wszystkie rekordy w jednej wybranej instrukcji. Jest to lepsze niż
JOIN
pobieranie niewielkiej grupy tych rekordów, pojedynczo, jako podkomponentu innego zapytania. Następnie analizuję go za pomocą kodu po stronie serwera, który wygląda mniej więcej tak ...Kiedy nie używać JOIN do optymalizacji
JOIN
Tworzenie dużej grupy rekordów w oparciu o relację jeden do jednego z jednym rekordem zapewnia optymalną wydajność w porównaniu z wielomaSELECT
instrukcjami, jeden po drugim, które po prostu pobierają następny typ rekordu.Ale
JOIN
jest nieefektywny w przypadku uzyskiwania rekordów w relacji jeden do wielu.Przykład: Baza danych Blogi zawiera 3 interesujące tabele: Post na blogu, Znacznik i Komentarz.
Jeśli jest 1 post na blogu, 2 tagi i 2 komentarze, otrzymasz wyniki takie jak:
Zwróć uwagę, jak każdy rekord jest zduplikowany. OK, więc 2 komentarze i 2 tagi to 4 rzędy. A co jeśli mamy 4 komentarze i 4 tagi? Nie dostajesz 8 rzędów - dostajesz 16 rzędów:
Dodaj więcej tabel, więcej rekordów itp., A problem szybko rozwinie się do setek wierszy, które są pełne w większości nadmiarowych danych.
Ile kosztują te duplikaty? Pamięć (na serwerze SQL i kod, który próbuje usunąć duplikaty) i zasoby sieciowe (między serwerem SQL a serwerem kodu).
Źródło: https://dev.mysql.com/doc/refman/8.0/en/nested-join-optimization.html ; https://dev.mysql.com/doc/workbench/en/wb-relationship-tools.html
źródło
Skonstruuj zarówno oddzielne zapytania, jak i połączenia, a następnie zmień czas na każde z nich - nic nie pomaga bardziej niż liczby w świecie rzeczywistym.
Jeszcze lepiej - dodaj „EXPLAIN” na początku każdego zapytania. Dzięki temu dowiesz się, ile podzapytań używa MySQL, aby odpowiedzieć na Twoje żądanie danych, oraz ile wierszy skanuje dla każdego zapytania.
źródło
W zależności od złożoności bazy danych w porównaniu ze złożonością programisty, może być prostsze wykonanie wielu wywołań SELECT.
Spróbuj uruchomić statystyki bazy danych zarówno dla JOIN, jak i dla wielu SELECTS. Sprawdź, czy w Twoim środowisku JOIN jest szybsze / wolniejsze niż SELECT.
Z drugiej strony, jeśli zmiana na JOIN oznaczałaby dodatkowy dzień / tydzień / miesiąc pracy deweloperskiej, trzymałbym się wielu SELECT
Twoje zdrowie,
BLT
źródło
Z mojego doświadczenia wynika, że zwykle szybsze jest uruchamianie kilku zapytań, szczególnie podczas pobierania dużych zestawów danych.
Podczas interakcji z bazą danych z innej aplikacji, takiej jak PHP, istnieje argument, że jedna podróż do serwera jest większa niż wiele.
Istnieją inne sposoby, aby ograniczyć liczbę podróży do serwera i nadal uruchamiać wiele zapytań, które często są nie tylko szybsze, ale także ułatwiają czytanie aplikacji - na przykład mysqli_multi_query.
Nie jestem nowicjuszem, jeśli chodzi o SQL, myślę, że istnieje tendencja wśród programistów, zwłaszcza juniorów, do spędzania dużo czasu na pisaniu bardzo sprytnych łączeń, ponieważ wyglądają inteligentnie, podczas gdy w rzeczywistości istnieją sprytne sposoby wydobywania danych, które wyglądają prosty.
Ostatni akapit był osobistą opinią, ale mam nadzieję, że to pomoże. Zgadzam się jednak z innymi, którzy mówią, że powinieneś testować. Żadne podejście nie jest srebrną kulą.
źródło
To, czy powinieneś używać złączenia, zależy przede wszystkim od tego, czy połączenie ma sens . Dopiero w tym momencie wydajność jest nawet czymś, co należy wziąć pod uwagę, ponieważ prawie we wszystkich innych przypadkach będzie to znacznie gorsze wydajność .
Różnice w wydajności będą w dużej mierze związane z tym, jak powiązane są informacje, o które prosisz. Łączy pracę i działa szybko, gdy dane są powiązane i poprawnie indeksujesz elementy, ale często skutkują pewną redundancją, a czasem większą liczbą wyników niż potrzeba. A jeśli twoje zbiory danych nie są bezpośrednio powiązane, umieszczenie ich w jednym zapytaniu da w wyniku tak zwany iloczyn kartezjański (w zasadzie wszystkie możliwe kombinacje wierszy), co prawie nigdy nie jest tym, czego chcesz.
Jest to często spowodowane relacjami „wiele do jednego do wielu”. Na przykład odpowiedź HoldOffHungera wspominała o jednym zapytaniu dotyczącym postów, tagów i komentarzy. Komentarze są powiązane z postem, tak jak tagi ... ale tagi nie są związane z komentarzami.
W takim przypadku zdecydowanie lepiej jest, aby były to co najmniej dwa oddzielne zapytania. Jeśli spróbujesz połączyć tagi i komentarze, ponieważ nie ma między nimi bezpośredniego związku, otrzymasz każdą możliwą kombinację tagu i komentarza.
many * many == manymany
. Poza tym, ponieważ posty i tagi nie są ze sobą powiązane, możesz wykonać te dwa zapytania równolegle, co prowadzi do potencjalnego zysku.Rozważmy jednak inny scenariusz: chcesz, aby komentarze były dołączone do posta i dane kontaktowe komentujących.
W tym miejscu powinieneś rozważyć dołączenie. Oprócz tego, że jest znacznie bardziej naturalnym zapytaniem, większość systemów baz danych (w tym MySQL) ma wielu inteligentnych ludzi, którzy wkładają dużo pracy w optymalizację zapytań, tak jak to. W przypadku oddzielnych zapytań, ponieważ każde zapytanie zależy od wyników poprzedniego, zapytania nie mogą być wykonywane równolegle, a całkowity czas staje się nie tylko faktycznym czasem wykonywania zapytań, ale także czasem spędzonym na pobieraniu wyników, przesiewaniu za ich pośrednictwem w poszukiwaniu identyfikatorów dla następnego zapytania, łączenia wierszy itp.
źródło
Czy będzie szybszy pod względem przepustowości? Prawdopodobnie. Ale może również blokować więcej obiektów bazy danych naraz (w zależności od bazy danych i schematu), a tym samym zmniejsza współbieżność. Z mojego doświadczenia wynika, że ludzie często są wprowadzani w błąd argumentem „mniej połączeń do bazy danych w obie strony”, podczas gdy w rzeczywistości w większości systemów OLTP, w których baza danych znajduje się w tej samej sieci LAN, prawdziwym wąskim gardłem rzadko jest sieć.
źródło
Oto link ze 100 przydatnymi zapytaniami, które są testowane w bazie danych Oracle, ale pamiętaj, że SQL jest standardem, czym różnią się między Oracle, MS SQL Server, MySQL i innymi bazami danych to dialekt SQL:
http://javaforlearn.com/100-sql-queries-learn/
źródło
Istnieje kilka czynników, co oznacza, że nie ma odpowiedzi binarnej. Pytanie, co jest najlepsze dla wydajności, zależy od środowiska. Nawiasem mówiąc, jeśli twój pojedynczy wybór z identyfikatorem nie jest podsekundą, coś może być nie tak z twoją konfiguracją.
Prawdziwym pytaniem, które należy zadać, jest to, w jaki sposób chcesz uzyskać dostęp do danych. Pojedyncze wybory obsługują późne wiązanie. Na przykład, jeśli potrzebujesz tylko informacji o pracownikach, możesz wybrać je z tabeli Pracownicy. Relacje klucza obcego mogą być używane do pobierania powiązanych zasobów w późniejszym czasie i w razie potrzeby. Wybrane elementy będą już miały klucz do wskazania, więc powinny być niezwykle szybkie, a Ty musisz tylko odzyskać to, czego potrzebujesz. Zawsze należy brać pod uwagę opóźnienia w sieci.
Połączenia będą pobierać wszystkie dane naraz. Jeśli generujesz raport lub wypełniasz siatkę, może to być dokładnie to, czego chcesz. Skompilowane i zoptymalizowane łączenia będą po prostu szybsze niż pojedyncze selekcje w tym scenariuszu. Pamiętaj, że łączenia ad-hoc mogą nie być tak szybkie - powinieneś je skompilować (do przechowywanego procesu). Szybka odpowiedź zależy od planu wykonania, który szczegółowo określa, jakie kroki podejmuje DBMS w celu pobrania danych.
źródło
Tak, jedno zapytanie wykorzystujące JOINS byłoby szybsze. Chociaż bez znajomości relacji między tabelami, do których wysyłasz zapytanie, rozmiaru zbioru danych lub lokalizacji kluczy podstawowych, prawie niemożliwe jest określenie, o ile szybciej.
Dlaczego nie przetestować obu scenariuszy, wtedy będziesz wiedział na pewno ...
źródło