Performance dell'indice su ON rispetto a WHERE


26

Ho due tavoli

@T1 TABLE
(
    Id INT,
    Date DATETIME
)

@T2 TABLE
(
    Id INT,
    Date DATETIME
)

Queste tabelle hanno un indice non cluster su (Id, Data)

E mi unisco a questi tavoli

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
WHERE 
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Questo può anche essere scritto come

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
    AND
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

La mia domanda è: quale di queste due query offre prestazioni migliori e perché? O sono uguali?


1
Hai davvero una variabile @table variata con un indice non cluster che copre tutti i campi e nessun indice cluster? o è solo una semplificazione?
Remus Rusanu,

1
È un'estrema semplificazione
Erik Bergstedt il

Risposte:


32

La performance sarà la stessa. L'ottimizzatore lo riconoscerà e creerà lo stesso piano.

D'altra parte non direi che sono uguali. Il primo modulo nella domanda è molto più leggibile e generalmente previsto.

Per un esempio usando alcune tabelle che ho a portata di mano puoi vedere che il piano di esecuzione è esattamente lo stesso, non importa come scrivo la query.

Dovresti essere in grado di determinare i piani di query per le tue tabelle e il tuo set di dati in modo da poter vedere cosa succede nella tua situazione.

SELECT * FROM salestable , custtable 
WHERE salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable 
JOIN  custtable 
ON salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable JOIN custtable 
ON salestable.custaccount = custtable.accountnum 
WHERE salestable.dataareaid = custtable.dataareaid

Fornisce questi piani di esecuzione

inserisci qui la descrizione dell'immagine


Sono d'accordo, il primo modulo è più facile da leggere e sono quindi sollevato dal fatto che siano uguali. Userò questo modulo solo in futuro.
Erik Bergstedt,

@ErikBergstedt Ho modificato la mia risposta, dovresti essere in grado di verificarlo abbastanza facilmente per il tuo set di dati e la struttura della tabella quando guardi i piani di esecuzione
Tom V - Team Monica

Si l'ho fatto. Grazie. Stavo solo cercando una seconda opinione poiché non ho trovato una risposta esistente.
Erik Bergstedt,

Nota: sono SOLO uguali se è un INNER JOIN. Se lanci OUTER JOINdentro, non sono decisamente gli stessi.
Kenneth Fisher,

22

Sono semanticamente identici e l'ottimizzatore non dovrebbe avere problemi a riconoscere questo fatto e generare piani identici.

Tendo a mettere le condizioni che fanno riferimento a entrambe le tabelle nella ONe condizioni che fanno riferimento a una sola tabella nella WHERE.

Per lo OUTER JOINSspostamento, tuttavia, le condizioni possono influire sulla semantica.


7

In casi semplici, sarà lo stesso. Tuttavia, ho visto query molto complesse con diversi join con piani significativamente diversi. Una recente a cui stavo lavorando è iniziata con una tabella che ha quasi 6 milioni di righe unite a circa 20 tabelle diverse. Solo il primo join a questo tavolo è stato un join interno , tutti gli altri sono stati lasciati join esterni. Il filtro nella clausola where è stato parametrizzato in questo modo:

WHERE table1.begindate >= @startdate AND table1.enddate < @enddate 

Questo filtro è stato utilizzato più avanti nel piano anziché in precedenza. Quando ho spostato queste condizioni sul primo join interno, il piano è cambiato radicalmente poiché il filtro è stato applicato all'inizio del piano per limitare il set di risultati e la mia CPU e il tempo trascorso sono scesi di circa il 310%. Quindi, come con molte domande di SQL Server, dipende.


2
Potresti aggiungere ulteriori dettagli - forse schermate dei diagrammi del piano di esecuzione - poiché la tua risposta sembra contraddire tutti gli altri?
Kenny Evitt,

2
Il piano ha mostrato un timeout di ottimizzazione?
Martin Smith,

In che modo il carico della CPU può diminuire di oltre il 100%?
Michael Green,

2

In generale, dove metti i filtri fa la differenza.
Mentre Tom V afferma che lo Strumento per ottimizzare riconoscerà che le query sono uguali e escogitano lo stesso piano, ciò non è sempre vero. Dipende dalla versione di SQL in uso, dalla complessità della query e dall'importanza per il batch complessivo che Optimizer determina della query.

L'ottimizzatore può decidere che questa parte del batch non valga la pena spendere abbastanza tempo per consentirgli di elaborare il piano migliore. In generale, si ottengono prestazioni migliori se si inseriscono condizioni che riducono la quantità di dati su cui la query dovrà lavorare nella clausola ON anziché nella clausola WHERE (se possibile, poiché farlo con un join esterno si tradurrà in un prodotto cartesiano .)

È un po 'più facile per lo sviluppatore SQL occasionale individuare i filtri nella clausola WHERE, ma ho lavorato su alcune tabelle di grandi dimensioni in cui i filtri nella clausola ON riducono le ore del tempo di esecuzione.

Quindi, se la clausola ha il potenziale per ridurre drasticamente il numero di righe che la query leggerà, la inserirò sempre nella clausola ON per aiutare l'Ottimizzatore a scegliere il piano migliore.


1

In circostanze normali, le condizioni del filtro possono essere specificate nelle clausole WHERE o JOIN. Tendo a posizionare i filtri sotto WHERE a meno che la precedenza OUTER JOIN non possa essere influenzata (vedi sotto) o se il filtro è molto specifico per quella tabella (es. TYPE = 12 per specificare un sottoinsieme specifico di righe nella tabella).

D'altra parte, entrambe le clausole ON e WHERE possono essere utilizzate per specificare le condizioni di join (anziché le condizioni di filtro). Finché stai usando solo i join INNER, non importa quale usi in circostanze normali.

Se si utilizzano i join OUTER, tuttavia, può fare una grande differenza. Se, ad esempio, specifichi un OUTER JOIN tra due tabelle (t1 e t2) ma poi, nella clausola WHERE, vai avanti per specificare una relazione eqijoin tra le tabelle (ad esempio t1.col = t2.col), hai appena ha convertito il join OUTER in un join INNER! Questo perché WHERE può essere usato per specificare un equijoin (o forse anche OUTER join, a seconda della versione, usando la sintassi deprecata * =) senza usare una clausola ON, e quando WHERE indica un equijoin interno tra le tabelle, sovrascrive un OUTER ISCRIVITI (se presente).

La domanda originale riguardava i filtri, in cui il tipo di join spesso non dovrebbe essere un problema, ma un join può anche fungere da filtro e in quelle situazioni il posizionamento della condizione di join può certamente importare.


-1

Con INNER JOINs, è un problema di stile.

Tuttavia, diventa molto più interessante con OUTER JOINs. È necessario esplorare le differenze tra le query con OUTER JOIN e le condizioni sia nella clausola ON che nella clausola WHERE. Il set di risultati non è sempre lo stesso. Ad esempio è

OUTER JOIN dbo.x ON a.ID = x.ID ... WHERE x.SomeField IS NOT NULL

lo stesso di

INNER JOIN dbo.x ON a.ID = x.ID AND x.SomeField IS NOT NULL

8
Se il risultato è diverso (che è ovviamente), a che serve confrontare le prestazioni?
ypercubeᵀᴹ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.