Join SQL espliciti vs impliciti


399

C'è qualche differenza di efficienza in un join interno esplicito vs implicito? Per esempio:

SELECT * FROM
table a INNER JOIN table b
ON a.id = b.id;

vs.

SELECT a.*, b.*
FROM table a, table b
WHERE a.id = b.id;

11
Buona domanda. Sono curioso di sapere perché viene utilizzato il join esplicito. Non è possibile fare tutte le query senza di essa?
Andrew

6
usa la parola chiave EXPLAIN per conoscere la differenza in entrambe le query .. usa JOIN e vedi la differenza .. Se provi in ​​una tabella con più di 100.000 record puoi vedere la differenza ...
Jeyanth Kumar

@andrew La mia domanda era in realtà se il join implicito fosse una forma di "hack" (come in "Una query che coinvolge più di una tabella, che non utilizza un join? È un hack vero?")
bobobobo

3
Sono diversi, l'unione implicita ti sorprenderà di tanto in tanto quando hai a che fare con valori nulli; usa l'unione esplicita ed evita i bug che sorgono quando "nulla è cambiato!"
BlackTigerX,

1
Non c'è differenza. ,è CROSS JOINcon rilegatura più flessibile ed INNER JOINè CROSS JOINcon rilegatura ONsimile WHEREma più stretta. Ciò che conta per l'esecuzione è come il DBMS ottimizza le query.
philipxy,

Risposte:


132

Per quanto riguarda le prestazioni, sono esattamente le stesse (almeno in SQL Server).

PS: tenere presente che la IMPLICIT OUTER JOINsintassi è obsoleta da SQL Server 2005. (La IMPLICIT INNER JOINsintassi utilizzata nella domanda è ancora supportata)

Deprecazione della sintassi JOIN "Old Style": solo una cosa parziale


4
@lomaxx, solo per chiarezza, potresti specificare quale sintassi dei 2 nella domanda è obsoleta?
J Wynia,

8
Potete fornire documentazione di supporto? Sembra sbagliato su più livelli.
NotMe

21
Come deprezzare lo standard SQL?
David Crawshaw,

7
@david Crenshaw, il join implicito non è più nello standard e non esiste da 18 anni.
HLGEM,

11
I cosiddetti "join impliciti" della varietà "interna" o "incrociata" rimangono nello standard. SQL Server sta deprecando la sintassi del join esterno "vecchio stile" (ie *=e =*) che non è mai stata standard.
Onedayquen

129

Personalmente preferisco la sintassi del join in quanto rende più chiaro che le tabelle sono unite e come sono unite. Prova a confrontare query SQL più grandi in cui selezioni tra 8 diverse tabelle e hai un sacco di filtri nel dove. Utilizzando la sintassi di join, si separano le parti in cui le tabelle sono unite, alla parte in cui si stanno filtrando le righe.


4
Sono completamente d'accordo, ma questo è un po 'fuori tema. OP ha chiesto informazioni sull'efficienza.
villasv,

56

Su MySQL 5.1.51, entrambe le query hanno piani di esecuzione identici:

mysql> explain select * from table1 a inner join table2 b on a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.02 sec)

mysql> explain select * from table1 a, table2 b where a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.00 sec)

table1ha 166208 file; table2ha circa 1000 file.

Questo è un caso molto semplice; non dimostra in alcun modo che Query Optimizer non si confonderebbe e non genererebbe piani diversi in un caso più complicato.


Questa dovrebbe essere la risposta accettata. Questo è corretto, il piano è lo stesso (o vicino a dichiarazioni più grandi) ma la quantità di record sarà drastica, causando così differenze nelle prestazioni.
SovietFrontier,

37

La seconda sintassi ha la possibilità indesiderata di un cross join: è possibile aggiungere tabelle alla parte FROM senza la corrispondente clausola WHERE. Questo è considerato dannoso.


Cosa succede se i nomi delle tabelle nella clausola from sono generati dalle tabelle utilizzate nella clausola where?
Jus12,

puoi fare un cross join anche con la sintassi JOIN esplicita. ( stackoverflow.com/a/44438026/929164 ) probabilmente intendevi che è meno rigoroso, quindi più soggetto a errori dell'utente.
Daniel Dubovski,

15

La prima risposta che hai dato utilizza la cosiddetta sintassi del join ANSI, l'altra è valida e funzionerà in qualsiasi database relazionale.

Sono d'accordo con grom che dovresti usare la sintassi del join ANSI. Come hanno detto, il motivo principale è la chiarezza. Invece di avere una clausola where con molti predicati, alcuni dei quali uniscono tabelle e altri che limitano le righe restituite con la sintassi del join ANSI, stai chiarendo in modo accecante quali condizioni vengono utilizzate per unire le tue tabelle e quali vengono utilizzate per limitare il risultati.


5

Per quanto riguarda le prestazioni, sono esattamente le stesse (almeno in SQL Server) ma attenzione che stanno deprecando questa sintassi del join e non è supportata da sql server2005 pronto all'uso.

Penso che tu stia pensando agli operatori deprecati * = e = * rispetto a "join esterno".

Ho appena testato i due formati indicati e funzionano correttamente su un database SQL Server 2008. Nel mio caso hanno prodotto piani di esecuzione identici, ma non potevo dire con certezza che ciò sarebbe sempre vero.


5

@lomaxx: Giusto per chiarire, sono abbastanza certo che entrambe le sintassi sopra sono supportate da SQL Serv 2005. Tuttavia, la sintassi di seguito NON è supportata

select a.*, b.*  
from table a, table b  
where a.id *= b.id;

In particolare, il join esterno (* =) non è supportato.


2
Francamente non lo userei nemmeno in SQL Server 2000, la sintassi * = spesso dà risposte sbagliate. A volte li interpreta come cross join.
HLGEM,

2

In alcuni database (in particolare Oracle), l'ordine dei join può fare un'enorme differenza per le prestazioni delle query (se sono presenti più di due tabelle). Su una domanda, in alcuni casi avevamo letteralmente due ordini di differenza di grandezza. L'uso della sintassi del join interno ti dà il controllo su questo - se usi la sintassi dei suggerimenti giusti.

Non hai specificato quale database stai usando, ma la probabilità suggerisce SQL Server o MySQL dove non fa alcuna differenza.


1
Leigh, puoi usare anche i suggerimenti nei join impliciti.
SquareCog,

1
In Oracle è estremamente raro che l'ordine di join influenzi in modo significativo il piano di esecuzione. Vedi questo articolo di Jonathan Lewis per una spiegazione.
Jon Heller,

1

Come ha affermato Leigh Caldwell, Query Optimizer è in grado di produrre diversi piani di query in base a ciò che sembra funzionalmente simile alla stessa istruzione SQL. Per ulteriori approfondimenti, dai un'occhiata ai seguenti due post sul blog: -

Un post del team Oracle Optimizer

Un altro post dal blog "Dati strutturati"

Spero che lo trovi interessante.


Mike, la differenza di cui stanno parlando è che devi essere sicuro che se specifichi un join esplicito, specifichi la condizione di join su cui partecipare, non il filtro. Noterai che per le query semanticamente corrette, il piano exec è lo stesso.
SquareCog,

1

Per quanto riguarda le prestazioni, non dovrebbe fare alcuna differenza. La sintassi del join esplicito mi sembra più pulita in quanto definisce chiaramente le relazioni tra le tabelle nella clausola from e non ingombra la clausola where.


0

Fondamentalmente, la differenza tra i due è che uno è scritto alla vecchia maniera, mentre l'altro è scritto alla maniera moderna. Personalmente, preferisco la sceneggiatura moderna usando le definizioni interne, sinistra, esterna, destra perché sono più esplicative e rendono il codice più leggibile.

Quando si ha a che fare con i join interni non vi è alcuna reale differenza nella leggibilità, tuttavia, può risultare complicato quando si gestiscono i join left e right come nel metodo precedente si otterrebbe qualcosa del genere:

SELECT * 
FROM table a, table b
WHERE a.id = b.id (+);

Quanto sopra è il vecchio modo in cui viene scritto un join sinistro in contrapposizione al seguente:

SELECT * 
FROM table a 
LEFT JOIN table b ON a.id = b.id;

Come puoi vedere visivamente, il modo moderno di come viene scritto lo script rende la query più leggibile. (A proposito, lo stesso vale per i giunti giusti e un po 'più complicato per i giunti esterni).

Tornando alla piastra della caldaia, non fa differenza per il compilatore SQL il modo in cui viene scritta la query in quanto li gestisce allo stesso modo. Ho visto un mix di entrambi nei database Oracle che hanno coinvolto molte persone, sia i più vecchi che i più giovani. Ancora una volta, si riduce a quanto sia leggibile la sceneggiatura e il team con cui stai sviluppando.


-1

Nella mia esperienza, l'uso della sintassi cross-join-with-a-where-where produce spesso un piano di esecuzione danneggiato dal cervello, soprattutto se si utilizza un prodotto Microsoft SQL. Il modo in cui SQL Server tenta di stimare il numero di righe della tabella, ad esempio, è terribilmente orribile. L'uso della sintassi del join interno offre un certo controllo su come viene eseguita la query. Quindi, da un punto di vista pratico, data la natura atavica dell'attuale tecnologia di database, devi andare con l'unione interna.


5
Ne hai qualche prova? Perché la risposta accettata dice il contrario.
cimmanon,
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.