Utilizzando la parola chiave JOIN o no


45

Le seguenti query SQL sono le stesse:

SELECT column1, column2
FROM table1, table2
WHERE table1.id = table2.id;

SELECT column1, column2
FROM table1 JOIN table2 
ON table1.id = table2.id;

E certamente si traducono negli stessi piani di query su ogni DBMS che abbia mai provato.

Ma ogni tanto leggo o ascolto un'opinione secondo cui uno è decisamente migliore dell'altro. Naturalmente, queste affermazioni non sono mai giustificate da una spiegazione.

Dove lavoro, la seconda versione sembra essere favorita dalla maggior parte degli altri sviluppatori, quindi tendo anche a quello stile per ridurre al minimo la sorpresa. Ma nel mio cuore, sto davvero pensando al primo (poiché è così che l'ho imparato in origine).

Una di queste forme è oggettivamente migliore dell'altra? In caso contrario, quali sarebbero i motivi per usarne uno rispetto all'altro?


1
Perché non profilarlo e far conoscere il risultato a tutti noi? In generale, le prestazioni superano di gran lunga le preferenze di stile.
Demian Brecht,

3
"risulta negli stessi piani di query su tutti i DBMS che abbia mai provato" Se questo potesse avere una risposta in termini di prestazioni, l'avrebbe chiesto su stackoverflow.com. ahimè, sono la stessa query.
SingleNegationElimination

Ah .. Mi mancava :)
Demian Brecht,

2
"Soggettivo" non significa "qual è la tua opinione". Ho modificato questo tipo di soddisfare i criteri stabiliti nel FAQ .
Aaronaught

Tendo anche a quello stile per ridurre al minimo la sorpresa, penso che tu abbia appena risposto alla tua domanda. Le sorprese sono cattive.
Pieter B,

Risposte:


60

Trovo che la seconda forma sia migliore. Forse perché è così che l'ho imparato, lo ammetto, ma ho una ragione concreta: la separazione delle preoccupazioni. Mettere i campi che si stanno utilizzando per unire le tabelle nella clausola where può portare a difficoltà nella comprensione delle query.

Ad esempio, prendi la seguente query:

select *
from table1, table2, table3, table4
where table1.id = table2.id
and table2.id = table3.id
and table3.id = table4.id
and table1.column1 = 'Value 1'

La query sopra ha condizioni di unione delle tabelle e condizioni logiche aziendali effettive tutte combinate in un unico spazio. Con una query di grandi dimensioni, questo può essere molto difficile da capire.

Tuttavia, ora prendi questo codice:

select *
from table1 join table2 on table1.id = table2.id
join table3 on table2.id = table3.id
join table4 on table3.id = table4.id
where table1.column1 = 'Value 1'

In questo caso, tutto ciò che ha a che fare con le tabelle o il modo in cui sono correlate è tutto isolato dalla clausola from, mentre la logica aziendale effettiva per la restrizione della query è nella clausola where. Penso che sia molto più comprensibile, in particolare per le query più grandi.


Questo è l'unico modo sensato per farlo soprattutto dopo aver superato due tavoli o se hai bisogno di una combinazione di join sinistro, destro e completo.
aglassman,

5
+1 Per i join "separazione delle preoccupazioni" si uniscono i dati, dove le clausole determinano i sottoinsiemi di dati a cui si è interessati.

39

La sintassi del join ha sostituito la vecchia sintassi della virgola nel 1992. Al momento non vi è motivo di scrivere codice con la sintassi della virgola. Non ottieni nulla e sei soggetto ad alcuni problemi che semplicemente non hai con la sintassi esplicita.

In primo luogo quando si ottengono query più complicate è molto semplice eseguire un cross join accidentale mancando una condizione where. Questo è qualcosa che la sintassi di join esplicita può impedire che si verifichi poiché si verificherà un errore di sintassi.

Se si intende un cross join, la sintassi del join esplicito lo renderà chiaro mentre nella sintassi implicita qualcuno che esegue la manutenzione può presumere che si sia dimenticato di aggiungere la clausola where.

Quindi c'è il problema dei join left e right che sono problematici in almeno alcuni dbs usando la sintassi implicita. Sono deprecati in SQL Server e in effetti non restituiscono risultati corretti in modo affidabile anche nelle versioni precedenti. Nessuna query che necessita di un join esterno deve contenere la sintassi implicita in SQL Server.

Inoltre, ho visto domande qui e su altri siti in cui si sono verificati risultati errati quando le persone mescolano i join impliciti ed espliciti (ad esempio quando si aggiunge un join sinistro), quindi è una cattiva idea mescolarli.

Infine, molte persone che usano i join impliciti in realtà non capiscono i join. Questa è una comprensione fondamentale che devi avere per interrogare efficacemente un database.


Grazie per la spiegazione. Quando mi è stato insegnato, ci hanno mostrato entrambe la sintassi, ma la differenza non è stata spiegata. A volte sono riuscito a produrre query con mancante dov'è che, francamente, avrebbe aumentato la quantità di scrittura semplicemente unendo esplicitamente in primo luogo.
Awiebe,

8

Ha. Mi è capitato di trovare una possibile risposta alla mia domanda, mentre guardavo la documentazione di PostgreSQL . Per riassumere ciò che questa pagina spiega, la query risultante è sempre la stessa, ma il numero di piani che l'ottimizzatore deve considerare aumenta in modo esponenziale con il numero di join.

Dopo circa sei di questi join, il numero è così grande che il tempo per pianificare la query potrebbe essere evidente e dopo circa dieci l'ottimizzatore passerà da una ricerca esaustiva di piani a una ricerca probabilistica e potrebbe non arrivare al piano ottimale .

Impostando un parametro di runtime, è possibile indicare al pianificatore di trattare i join interni e incrociati esplicitamente menzionati in modo diverso dai join impliciti, forzandoli in cima al piano e non esplorando altre opzioni.

Da notare che il comportamento predefinito è lo stesso in entrambi i casi e che ottenere piani alternativi richiede la conoscenza degli interni dei dbms e delle peculiarità delle tabelle in questione per ottenere un risultato diverso


2
Tuttavia, hai leggermente frainteso questi documenti. Innanzitutto, ci sono in realtà tre soglie. Uno spara il GEQO come hai sottolineato; gli altri due (da e verso i limiti di collasso) finiscono per far aderire la pialla alla selezione degli indici applicabili anziché riorganizzare l'ordine dei join. In secondo luogo e altrettanto importante, le query vengono riscritte man mano che vengono analizzate. Ciò comporta che la prima delle query di esempio venga analizzata nello stesso albero delle query della seconda, le soglie quindi comunicano a PG se deve tentare di riordinare i join o meno.
Denis de Bernardy,

8

Bene, ecco la visione della teoria degli insiemi:

Quando si utilizza una virgola per separare due (o più) nomi di tabella, ciò che si intende è il prodotto cartesiano. Ogni riga della tabella "sinistra" verrà "abbinata" (concatenata) a quella della tabella destra.

Ora, se scrivi qualcosa nella clausola where, è come porre una condizione su questa "concatenazione" che dice a quali righe "concatenare" con quali righe.

In realtà si tratta di "unire" le righe :) e quindi la parola chiave join che aiuta a fornire una sintassi più leggibile ed è più comprensibile che tu voglia "davvero" unire alcuni valori comuni. Simile a ciò che @Dustin ha chiarito sopra.

Ora, ogni DBMS è intelligente, cioè non calcola prima il prodotto cartesiano e quindi filtra i dati (estremamente dispendioso) ma piuttosto lo fa in base alla struttura della query. L'unica cosa a cui riesco a pensare è che quando gli chiedi di "unirti" è come rendere esplicita l'attività di partecipazione e probabilmente aiuta a eseguire il codice più velocemente (di quanto? Dovrai profilarlo e vedere) ma nel caso separato da virgole, occorre del tempo per "capire" la strategia ottimale. Potrei sbagliarmi, ma sto solo facendo un'ipotesi colta su come si codificherebbe ...


5

Penso che sia generalmente meglio usare le istruzioni JOIN per quel caso.

Se, in futuro, si presenta una situazione che richiede la modifica dell'istruzione da un INNER JOIN a un OUTER JOIN, ciò sarà molto più facile da fare con la seconda istruzione.


3

Qualsiasi RDBMS li renderà la stessa cosa in termini di esecuzione. Dipende se si è più leggibili ed espressivi.

Usa JOIN in modo che sia chiaro cos'è la corrispondenza dei join e qual è la selezione effettiva, come in:

select name, deptname
from people p, departments d
where p.deptid = d.id and p.is_temp = 'Y'

vs.

select name, deptname
from people p
    inner join departments d on p.deptid = d.id
where p.is_temp = 'Y'

Quest'ultimo caso chiarisce immediatamente quale sia la condizione di join e quale sia il criterio di selezione.


1

Ho visto una volta sola i due risultati in un diverso set di ottimizzazioni e se la memoria serve era in ms-sql2k su una query davvero pelosa. In quell'esempio il vecchio modulo usato con * = ha portato a prestazioni 4x circa più veloci. Nessuno, compresi i nostri tecnici Microsoft, potrebbe mai spiegare il perché. I ragazzi della SM lo hanno etichettato come un errore. Non l'ho mai più visto.

Dal momento che la maggior parte dei RDBMS sono abbastanza intelligenti da non fare i cartesiani completi, il motivo principale per cui riesco a pensare di non usarlo (oltre a ciò è ammortizzato) è che la maggior parte delle persone con meno di 30-35 anni con cui ho lavorato non hanno mai visto vecchia forma prima e si perdono terribilmente quando la incontrano.


Naturalmente la sintassi del join sinistro non ha mai fornito i risultati corretti in modo affidabile (vedere BOL per SQL Server 2000), quindi anche se fosse più veloce, l'avrei sostituito.
HLGEM,

Non l'ho mai visto, e la ricerca con l'asterisco non finisce mai bene, hai un esempio?
Bill,

-1

Il vecchio stile è stato deprecato, non dovresti usarlo.

Non ci dovrebbe essere nemmeno un argomento su quale sia meglio o no. Il nuovo codice non dovrebbe usare la vecchia sintassi.


Penso che questa risposta non aggiunga davvero nulla senza dire perché è stata deprecata e non dovrebbe essere usata.
RemcoGerlich,

1
@RemcoGerlich perché è stato deprecato non è in discussione qui. Ciò che è in discussione qui è se usare la sintassi vecchia o nuova. Se uno è meglio dell'altro o no è discutibile: non dovresti usare la vecchia sintassi. La domanda sul perché è un'altra discussione. (uno che è stato risolto 20 anni fa.)
Pieter B,

-4

Uno dei motivi per la sintassi più concisa è che è più concisa, quindi se ti senti a tuo agio è più facile da leggere. Penso al caso verboso come simile alla scrittura di aritmetica in COBOL, ad esempio MULTIPLY A BY B DARE C.


Downvoter: c'è qualcosa di effettivamente errato in questa risposta, o sono stati semplicemente "in disaccordo con te" i voti negativi?
Adam Libuša,
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.