2012-03-29 16 views
12

Moje google-fu i so-fu zawodzą mnie tutaj, więc równie dobrze mogę zapytać.TSQL - Jaka jest właściwa kolejność łączenia tabel?

Mam wiele zapytań z wieloma złączeniami w nich.

W ramach jednego zapytania łączę nagłówek/element/szczegóły razem, a także szukam różnych bitów informacji dla tych rekordów.

Kiedy dołączam, staram się utrzymywać porządek w tym, w jaki sposób są powiązane. Np .: Mój nagłówek ma dwa tabele odnośników, więc dołączę do nich przed dołączeniem do mojej tabeli przedmiotów.

Czy to prawda?

Czy lepiej jest dołączyć do większych tabel przed tabelami odnośników? Lub odwrotnie?

Czy powinienem używać podpowiedzi loop podczas dołączania do małych tabel oraz podpowiedzi merge przy dołączaniu do openrowsets?

Jestem pewien, że odpowiedź brzmi: "to zależy", ale niektóre ogólne wskazówki dotyczące skutecznego i wydajnego łączenia będą bardzo pomocne. Dzięki!

+0

W większości przypadków nie trzeba określać typu łączenia (scalanie/pętla/hash). Jeśli tak, prawdopodobnie istnieją podstawowe problemy, które powinny zostać rozwiązane, zamiast dołączania podpowiedzi. –

+2

Jeśli nie wiesz dobrze, co robisz i rozumiesz plany wykonywania kwerend, NIGDY nie używaj wskazówek dotyczących kwerend. – JotaBe

Odpowiedz

12

EDYCJA: W oparciu o twoje pytania (i Kirk Woll) komentarz, powinieneś zrozumieć, że order of your joins is aesthetic, and does not directly impact the resulting execution plan. Optymalizator zapytań wykona połączenia w najbardziej wydajnej kolejności i użyje odpowiedniej operacji łączenia w przeważającej większości przypadków bez żadnych wskazówek.

Jeśli chodzi o estetykę porządku łączenia, jest to trochę subiektywne, ale powiedziałbym, że łączcie swoje tabele razem w jakiejkolwiek kolejności, która ma logiczny sens podczas czytania zapytania ... jeśli zaczniesz od @HeaderId, rozpocząć z tej tabeli, a następnie JOIN do tabel dzieci:

FROM 
    Header h 
    JOIN Items i ON h.HeaderId = i.HeaderId 
    JOIN Details d ON i.ItemId = d.ItemId 
WHERE 
    h.HeaderId = @HeaderId 

Ale jeśli zaczęło zapytanie o @DetailId, chciałbym przyłączyć się w odwrotnej kolejności.

FROM 
    Details d 
    JOIN Items i ON d.ItemId = i.ItemId 
    JOIN Header h ON i.HeaderId = h.HeaderId 
WHERE 
    d.DetailId = @DetailId 

To jednak subiektywne i tylko moje osobiste preferencje.

Staje się mniej subiektywny, gdy zaczynasz włączać OUTER JOIN s ... spróbuj ustrukturyzować zapytanie, aby uniknąć jakichkolwiek RIGHT OUTER JOIN s, a zamiast tego użyj LEFT OUTER JOIN.

Nie używaj domyślnie wskazówek dołączania ... w rzeczywistości prawie nigdy ich nie użyjesz. Optymalizator zapytań wykonuje bardzo dobrą pracę wybierając optymalny plan wykonania. Spotkałem tylko jedną instancję, w której musiałem podać podpowiedź, aby ulepszyć plan ... to drastycznie pomogło serwerowi, że kwerenda była uruchomiona w tym czasie, ale kiedy baza danych została zmigrowana na inny serwer, moja dołączona podpowiedź uszkodziła wydajność zapytania. Tak więc, aby powtórzyć, zazwyczaj nie jest dobrym pomysłem udzielanie wskazówek dotyczących dołączania.

+1

Być może OP nie jest świadomy, że kolejność łączenia jest nieistotna dla planu wykonania i jest czysto estetyczna? –

+0

@KirkWoll To bardzo dobry punkt, którego przeoczyłem ... wyjaśnię to w mojej odpowiedzi. –

+0

@Kirk, właśnie dlatego pytam. Zamówienie w ogóle nie ma znaczenia? – IronicMuffin

0

Porządek jest w dużej mierze [1] estetyczny, ale myślę, że warto mieć konwencję dotyczącą zarówno kolejności tabel, jak i warunków w warunkach NA, aby uniknąć nieporozumień.

Wskazówki dotyczące zapytań dotyczą wyłącznie wyjątkowych przypadków i chociaż mogą pojawić się sytuacje, w których trzeba z nich skorzystać (zwykle rezygnując z wydajności w celu zmniejszenia problemów związanych z współbieżnością), należy zawsze starać się znaleźć skuteczniejszy sposób rozwiązania problemu.

[1] znam jednego przypadku, w którym zamówienie ma znaczenia:

CREATE TABLE A (
    id int IDENTITY PRIMARY KEY, 
    name varchar 
); 

CREATE TABLE B (
    id int IDENTITY PRIMARY KEY, 
    a_id int FOREIGN KEY REFERENCES A (id), 
    name varchar 
); 

SELECT * 
FROM A 
INNER LOOP JOIN B on A.id = B.a_id; 

SELECT * 
FROM B 
INNER LOOP JOIN A on A.id = B.a_id; 

Pierwszy wybierz robi dwa skany indeksowych, drugi robi skanowanie oraz poszukują. To kolejny dobry powód, aby unikać podpowiedzi.

Powiązane problemy