Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Prestazioni INNER JOIN e LEFT JOIN in SQL Server

Un LEFT JOIN non è assolutamente più veloce di un INNER JOIN . In effetti, è più lento; per definizione, un outer join (LEFT JOIN o RIGHT JOIN ) deve fare tutto il lavoro di un INNER JOIN più il lavoro extra di estensione nulla dei risultati. Dovrebbe anche restituire più righe, aumentando ulteriormente il tempo di esecuzione totale semplicemente a causa delle dimensioni maggiori del set di risultati.

(E anche se un LEFT JOIN erano più veloce in specifico situazioni dovute a una confluenza di fattori difficile da immaginare, non è funzionalmente equivalente a un INNER JOIN , quindi non puoi semplicemente sostituire tutte le istanze di una con l'altra!)

Molto probabilmente i tuoi problemi di prestazioni risiedono altrove, ad esempio non avere una chiave candidata o una chiave esterna indicizzata correttamente. 9 tavoli è un bel po' da unirsi, quindi il rallentamento potrebbe letteralmente essere quasi ovunque. Se pubblichi il tuo schema, potremmo essere in grado di fornire maggiori dettagli.

Modifica:

Riflettendo ulteriormente su questo, potrei pensare a una circostanza in cui un LEFT JOIN potrebbe essere più veloce di un INNER JOIN , ed è quando:

  • Alcuni dei tavoli sono molto piccolo (diciamo, meno di 10 righe);
  • Le tabelle non hanno indici sufficienti per coprire la query.

Considera questo esempio:

CREATE TABLE #Test1
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test1 (ID, Name) VALUES (1, 'One')
INSERT #Test1 (ID, Name) VALUES (2, 'Two')
INSERT #Test1 (ID, Name) VALUES (3, 'Three')
INSERT #Test1 (ID, Name) VALUES (4, 'Four')
INSERT #Test1 (ID, Name) VALUES (5, 'Five')

CREATE TABLE #Test2
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test2 (ID, Name) VALUES (1, 'One')
INSERT #Test2 (ID, Name) VALUES (2, 'Two')
INSERT #Test2 (ID, Name) VALUES (3, 'Three')
INSERT #Test2 (ID, Name) VALUES (4, 'Four')
INSERT #Test2 (ID, Name) VALUES (5, 'Five')

SELECT *
FROM #Test1 t1
INNER JOIN #Test2 t2
ON t2.Name = t1.Name

SELECT *
FROM #Test1 t1
LEFT JOIN #Test2 t2
ON t2.Name = t1.Name

DROP TABLE #Test1
DROP TABLE #Test2

Se lo esegui e visualizzi il piano di esecuzione, vedrai che il INNER JOIN la query costa effettivamente più di LEFT JOIN , perché soddisfa i due criteri di cui sopra. È perché SQL Server vuole eseguire una corrispondenza hash per INNER JOIN , ma esegue cicli nidificati per LEFT JOIN; il primo è normalmente molto più veloce, ma poiché il numero di righe è così piccolo e non c'è un indice da usare, l'operazione di hashing risulta essere la parte più costosa della query.

Puoi vedere lo stesso effetto scrivendo un programma nel tuo linguaggio di programmazione preferito per eseguire un gran numero di ricerche su un elenco con 5 elementi, rispetto a una tabella hash con 5 elementi. A causa delle dimensioni, la versione della tabella hash è in realtà più lenta. Ma aumentalo a 50 elementi, o 5000 elementi, e la versione dell'elenco rallenta a una scansione, perché è O(N) contro O(1) per la tabella hash.

Ma cambia questa query in modo che sia su ID colonna invece di Name e vedrai una storia molto diversa. In tal caso, esegue cicli nidificati per entrambe le query, ma INNER JOIN versione è in grado di sostituire una delle scansioni dell'indice raggruppate con una ricerca, il che significa che questo sarà letteralmente un ordine di grandezza più veloce con un numero elevato di righe.

Quindi la conclusione è più o meno quella che ho menzionato in diversi paragrafi sopra; questo è quasi sicuramente un problema di indicizzazione o copertura dell'indice, eventualmente combinato con una o più tabelle molto piccole. Queste sono le uniche circostanze in cui SQL Server potrebbe a volte scegli un piano di esecuzione peggiore per un INNER JOIN di un LEFT JOIN .