Un join è ottimizzato per una clausola where in fase di esecuzione?


14

Quando scrivo una domanda come questa ...

select *
from table1 t1
join table2 t2
on t1.id = t2.id

L'ottimizzatore SQL, non sicuro se questo è il termine corretto, lo traduce in ...

select *
from table1 t1, table2 t2
where t1.id = t2.id

In sostanza, l'istruzione Join in SQL Server è solo un modo più semplice per scrivere sql? O è effettivamente utilizzato in fase di esecuzione?

Modifica: quasi sempre, e quasi sempre, userò la sintassi Join. Sono solo curioso di sapere cosa succede.


1
Potresti approfondire il "quasi"? Quando useresti la sintassi vecchio stile e perché?
Aaron Bertrand

2
Un caso limite in cui ciò fa la differenza è se aggiungi un (deprecato) GROUP BY ALLin
Martin Smith,

@MartinSmith qualcuno usa GROUP BY ALLapposta? :-)
Aaron Bertrand

@AaronBertrand - Ne dubito! Non pensare di aver mai visto nessuno usarlo.
Martin Smith,

Risposte:


20

Quelli collassano sulla stessa cosa internamente. Il primo è quello che dovresti sempre scrivere . Ancora più importante, perché è importante? Sono identici in termini di piano di esecuzione e prestazioni (supponendo che non si incasini, il che è più facile da fare con la sintassi pigra e vecchio stile).

Ecco la prova che utilizza AdventureWorks che non esiste CROSS JOINe filtercontinua.


L'unione esplicita:

inserisci qui la descrizione dell'immagine


L'unione implicita:

inserisci qui la descrizione dell'immagine


Guarda, mamma! Piani identici, risultati identici, nessun join incrociato o filtri visti da nessuna parte.

(Per chiarezza, l'avvertimento per l' SELECToperatore in entrambi i casi è una conversione implicita che influisce sulla cardinalità, nulla a che fare con l'unione in entrambi i casi.)


20

A rigor di termini, c'è una differenza nell'input per Query Optimizer tra i due moduli:

-- Input tree (ISO-89)
SELECT
    p.Name,
    Total = SUM(inv.Quantity)
FROM 
    Production.Product AS p,
    Production.ProductInventory AS inv
WHERE
    inv.ProductID = p.ProductID
GROUP BY
    p.Name
OPTION (RECOMPILE, QUERYTRACEON 8605, QUERYTRACEON 3604);

Albero di input ISO-89

-- Input tree (ISO-92)
SELECT
    p.Name,
    Total = SUM(inv.Quantity)
FROM Production.Product AS p
JOIN Production.ProductInventory AS inv ON
    inv.ProductID = p.ProductID
GROUP BY
    p.Name
OPTION (RECOMPILE, QUERYTRACEON 8605, QUERYTRACEON 3604);

Albero di input ISO-92

Come puoi vedere, il ONpredicato della clausola è strettamente legato al join usando la sintassi moderna. Con la sintassi precedente, esiste un join incrociato logico seguito da una selezione relazionale (un filtro di riga).

Query Optimizer comprime quasi sempre la selezione relazionale nel join durante l'ottimizzazione, il che significa che i due moduli produrranno molto probabilmente piani di query equivalenti, ma non esiste alcuna garanzia effettiva.


4

Per i join interni sono intercambiabili, ma per i join esterni hanno significati diversi: ON corrisponde e DOVE è semplice filtro. Quindi è meglio attenersi alla corrispondenza della sintassi JOIN corretta su ON.


4

OK, ero curioso, quindi ho fatto un test. Ho ottenuto piani di esecuzione reali per quanto segue.

select * 
from sys.database_principals prin, sys.database_permissions perm
WHERE prin.principal_id = perm.grantee_principal_id

e

select * 
from sys.database_principals prin
JOIN sys.database_permissions perm
    ON prin.principal_id = perm.grantee_principal_id

Li ho confrontati oggetto per oggetto ed erano identici. Quindi, almeno per un esempio molto semplice, sono usciti alla stessa cosa. Ho anche controllato le statistiche IO e il tempo ed erano abbastanza vicine da essere la stessa cosa.

Detto questo, dovresti usare la JOINsintassi perché è più facile da leggere e hai meno probabilità di commettere errori, in particolare nelle query complicate. E la sintassi *=/ =*per i OUTERjoin è già stata rimossa da SQL Server 2005.

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.