2012-03-29 4 views
12

Il mio google-fu e così-fu mi sta venendo a mancare qui, quindi tanto vale chiedere.TSQL - Qual è l'ordine corretto per unire le tabelle?

Ho molte query con più join in esse.

In una query, sto unendo intestazione/voce/dettagli insieme, così come guardando i vari bit di informazione per questi record.

Quando mi unisco, cerco di mantenere le cose in ordine di come sono correlate. Es .: La mia intestazione ha due tabelle di ricerca, quindi mi unirò a quelle prima di unirmi alla tabella dei miei articoli.

È corretto?

È meglio unirsi a tabelle più grandi prima delle tabelle di ricerca? O vice versa?

Devo utilizzare un suggerimento loop quando ci si unisce a piccoli tavoli e un suggerimento merge quando si uniscono a openrowsets?

Sono sicuro che la risposta è "dipende", ma alcune linee guida generali di entrare in modo efficace ed efficiente sarebbe molto utile. Grazie!

+0

Nella maggior parte dei casi non è necessario specificare il tipo di join (unione/loop/hash). Se lo fai ci sono probabilmente problemi sottostanti che dovrebbero essere risolti invece del cerotto di benvenuto. –

+2

A meno che tu non sappia bene cosa stai facendo e tu capisca i piani di esecuzione delle query, non utilizzare MAI i suggerimenti per le query. – JotaBe

risposta

12

EDIT: In base alle vostre domande (e di Kirk Woll) commento, è necessario comprendere che il order of your joins is aesthetic, and does not directly impact the resulting execution plan. Query Optimizer eseguirà i join nell'ordine più efficiente e utilizzerà l'operazione di join appropriata per la maggior parte del tempo senza alcun suggerimento.

Quando si tratta dell'estetica dell'ordine di join questo è un po 'soggettivo, ma direi unire le tabelle insieme in qualsiasi ordine abbia un senso logico durante la lettura della query ... se inizi con un @HeaderId, iniziare con quel tavolo, e poi JOIN ai tavoli per bambini:

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

Ma, se hai iniziato la tua ricerca con un @DetailId, vorrei unire in ordine inverso.

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

Tuttavia, questo è soggettivo e solo la mia preferenza personale.

Diventa meno soggettivo quando si inizia a includere OUTER JOIN s ... provare a strutturare la query per evitare qualsiasi RIGHT OUTER JOIN s, e invece utilizzare LEFT OUTER JOIN s.

Non utilizzare i suggerimenti di join per impostazione predefinita ... in realtà non li utilizzerai quasi mai. Query Optimizer fa un ottimo lavoro nella scelta del piano di esecuzione ottimale. Ho incontrato solo una singola istanza in cui avevo bisogno di fornire un suggerimento per migliorare il piano ... ha aiutato drasticamente sul server in cui la query era in esecuzione al momento, ma quando il database è stato migrato su un server diverso, il mio suggerimento di join ha distrutto le prestazioni della query. Quindi, per ribadire, di solito è una cattiva idea fornire suggerimenti per l'unione.

+1

Forse l'OP non è consapevole del fatto che l'ordine di unione è irrilevante per il piano di esecuzione ed è puramente estetico? –

+0

@KirkWoll Questo è un ottimo punto che ho trascurato ... lo chiarirò nella mia risposta. –

+0

@Kirk, è esattamente il motivo per cui lo sto chiedendo. L'ordine non è affatto rilevante? – IronicMuffin

0

L'ordine è in gran parte [1] estetico, ma penso che sia utile avere una convenzione per l'ordine delle tabelle e dei termini nelle condizioni ON, per evitare confusione.

I suggerimenti per le query sono solo per casi eccezionali e, mentre è possibile trovare situazioni in cui è necessario utilizzarli (in genere sacrificando le prestazioni per ridurre i problemi di concorrenza), è necessario cercare sempre un modo più efficace per risolvere il problema.

[1] So di un caso in cui l'ordine non importa:

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; 

Il primo select fa due scansioni di indice, la seconda fa una scansione e una ricerca. Questa è un'altra buona ragione per evitare suggerimenti.