L'uso del costrutto nella clausola JOIN può introdurre barriere di ottimizzazione in alcuni casi?


35

È stato portato alla mia attenzione che il USINGcostrutto (anziché ON) nella FROMclausola delle SELECTquery potrebbe introdurre barriere di ottimizzazione in alcuni casi.

Intendo questa parola chiave:

SELEZIONA *
Da un
ISCRIVITI b USANDO (a_id)

Solo in casi più complessi.

Contesto: questo commento a questa domanda .

Lo uso molto e non ho mai notato nulla finora. Sarei molto interessato a un caso di prova che dimostri l'effetto o eventuali collegamenti a ulteriori informazioni. I miei sforzi di ricerca si sono rivelati vuoti.

La risposta perfetto sarebbe un banco di prova per dimostrare USING (a_id)con prestazioni inferiori rispetto alle alternative unirsi clausola ON a.a_id = b.a_id- se che può realmente accadere.


2
@kgrittn: Questo è quello che generalmente mi aspettavo finora: USINGè leggermente più veloce , in quanto risulta in una colonna in meno nella matrice dei risultati. Le tue scoperte risalgono al 2005 e al 2008. Presumo che qualsiasi problema sia stato risolto ormai. Tuttavia , posso vedere una possibile limitazione: USINGpotrebbe essere necessario applicare i JOIN con l' ordine , poiché la colonna di unione risultante è un prodotto comune. In tal modo potenzialmente limitando le opzioni nel riordino dei JOIN.
Erwin Brandstetter,

1
Ho trovato questo thread che potrebbe aver avuto a che fare con il rimandarmi dall'usarlo tutte le volte che avevo, perché una VISTA con una condizione USING su un join può causare problemi in dump / restore: archives.postgresql.org/pgsql- bugs / 2011-06 / msg00030.php Ho ancora la sensazione assillante che ci sia stato un altro thread relativo a problemi di prestazioni con USING in cui la soluzione alternativa doveva usare ON, ma ho intenzione di rinunciare a trovarlo, credo. Probabilmente è sicuro usarlo al di fuori delle visualizzazioni e ricorda di provare ON invece come passaggio diagnostico se una query è lenta.
kgrittn,

1
Sembra che "usando" renda il codice un po 'leggibile ma immagino che entrambi i campi abbiano bisogno dello stesso nome. Non penso che l'utilizzo avrà prestazioni migliori di un "on", poiché il DB deve comunque effettuare la corrispondenza, è come se un select avesse le stesse prestazioni di un join (correggimi se sbaglio), il la differenza è che Join è più pulito e più facile da mantenere.
jcho360,

2
@HLGEM: è solo un nome simbolico e con solo due tabelle, come nel mio esempio, non c'è spazio per la confusione. Tuttavia, ho modificato la domanda. Non vorrei incoraggiare l'uso sfortunato di idcome nome di colonna.
Erwin Brandstetter,

2
@ChristiaanWesterbeek: non sono d'accordo. Il "luogo di riferimento" per la risposta di Postgres in profondità è (ancora) la corrispondenza. Solo pochissimi sviluppatori Postgres sono attivi su SO, ma tutti gli sviluppatori ed esperti Postgres leggono la mailing list
a_horse_with_no_name

Risposte:


12

Erwin: Concordo con l'idea che USARE causando ordini rigidi potrebbe creare molti casi limite in cui escludere piani ottimali. Di recente ho aiutato qualcuno che aveva qualcosa del genere nella sua query:

LEFT JOIN ( 
     a 
     JOIN b ON a.id = b.a_id
     JOIN c ON b.c_id = c.id
) ON a.id = something.a_id
LEFT JOIN (
     table1 t1
     JOIN table2 t2 ON t1.some_field = t2.other_field
     JOIN talbe3 t3 ON t2.yafield = t3.something_else
) ON ....
repeat a few more times

Nel suo caso il peggio di questi blocchi di join stava causando un join di loop nidificato attraverso circa 200k righe, circa 20k volte (fare i conti), e poiché i tasti non potevano essere trasferiti agli indici, era una scansione sequenziale. Ciò significa che l'esecuzione della query complessiva ha richiesto circa 3 ore a causa delle modifiche del piano a cascata. Distribuendo il join sinistro, le chiavi potevano essere spinte verso il basso e la query veniva eseguita in pochi secondi. Naturalmente questo non è esattamente equivalente, motivo per cui il pianificatore non può trattarli come equivalenti e quindi è stato lasciato a capire quel piano come un hash join e quindi fare un ciclo annidato, che era dolorosamente lento.

Ogni volta che forzate rigidamente i join a passare in un certo ordine, introducete casi in cui le informazioni sui filtri chiave potrebbero non essere ancora disponibili nell'esecuzione del piano, e quindi cosa potrebbe essere possibile fare in seguito in una rapida scansione dell'indice / join hash potrebbe essere necessario eseguire molto più lentamente in un ciclo nidificato / scansione sequenziale e quindi mentre il frammento sopra non è immediatamente equivalente, mostra lo stesso problema.

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.