In quale ordine vengono valutati i JOIN MySQL?
Domanda
Ho la seguente query:
SELECT c.*
FROM companies AS c
JOIN users AS u USING(companyid)
JOIN jobs AS j USING(userid)
JOIN useraccounts AS us USING(userid)
WHERE j.jobid = 123;
Ho le seguenti domande:
- La sintassi USING è sinonimo di sintassi ON?
- Questi join vengono valutati da sinistra a destra? In altre parole, questa query dice: x = aziende JOIN utenti; y = x lavori JOIN; z = y JOIN accountaccount;
- Se la risposta alla domanda 2 è affermativa, è sicuro supporre che la tabella delle aziende abbia colonne companyid, userid e jobid?
- Non capisco come la clausola WHERE possa essere utilizzata per selezionare le righe nella tabella delle società quando si riferisce all'alias "j".
Qualsiasi aiuto sarebbe apprezzato!
Soluzione
-
USARE (fieldname) è un modo abbreviato di dire ON table1.fieldname = table2.fieldname.
-
SQL non definisce l'ordine in cui vengono eseguiti i JOIN perché non è la natura della lingua. Ovviamente un ordine deve essere specificato nella dichiarazione, ma un INNER JOIN può essere considerato commutativo: puoi elencarli in qualsiasi ordine e otterrai gli stessi risultati.
Detto questo, durante la costruzione di un SELECT ... JOIN, in particolare uno che include LEIN JOIN, ho trovato sensato considerare il terzo JOIN come unire la nuova tabella ai risultati del primo JOIN, il quarto JOIN come unendo i risultati del secondo JOIN, e così via.
Più raramente, l'ordine specificato può influenzare il comportamento di Query Optimizer, a causa del modo in cui influenza l'euristica.
-
No. Il modo in cui viene assemblata la query richiede che sia le aziende che gli utenti dispongano di un ID azienda, i lavori abbiano un ID utente e un ID lavoro e gli account utente abbiano un ID utente. Tuttavia, solo una delle società o ha bisogno di un ID utente per far funzionare il JOIN.
-
La clausola WHERE sta filtrando l'intero risultato, ovvero tutte le colonne JOINed, utilizzando una colonna fornita dalla tabella dei lavori.
Altri suggerimenti
Non posso rispondere un po 'della sintassi USING. Quello è strano. Non l'ho mai visto prima, avendo sempre usato una clausola ON.
Ma ciò che posso sapere è che l'ordine delle operazioni JOIN è determinato dinamicamente da Query Optimizer quando costruisce il suo piano di query, basato su un sistema di euristica di ottimizzazione, alcuni dei quali sono:
-
Il JOIN viene eseguito su un campo chiave primaria? In tal caso, questo ha la massima priorità nel piano di query.
-
Il JOIN viene eseguito su un campo chiave esterna? Anche questo ha la massima priorità.
-
Esiste un indice nel campo unito? In tal caso, aumentare la priorità.
-
È stata eseguita un'operazione JOIN su un campo nella clausola WHERE? L'espressione della clausola WHERE può essere valutata esaminando l'indice (anziché eseguendo una scansione della tabella)? Questa è un'opportunità di ottimizzazione importante , quindi ha un grosso impatto prioritario.
-
Qual è la cardinalità della colonna unita? Le colonne con cardinalità elevata offrono all'ottimizzatore maggiori opportunità di discriminare le false corrispondenze (quelle che non soddisfano la clausola WHERE o la clausola ON), quindi i join con cardinalità elevata vengono generalmente elaborati prima dei join con cardinalità bassa.
-
Quante righe effettive ci sono nella tabella unita? Partecipare a una tabella con solo 100 valori creerà meno un'esplosione di dati rispetto a una tabella con dieci milioni di righe.
Comunque ... il punto è ... ci sono MOLTE variabili che vanno nel piano di esecuzione della query. Se vuoi vedere come MySQL ottimizza le sue query, usa la sintassi EXPLAIN.
Ed ecco un buon articolo da leggere:
http://www.informit.com/articles/article.aspx? p = 377652
ON EDIT:
Per rispondere alla tua quarta domanda: non stai interrogando le " società " tavolo. Stai interrogando il prodotto incrociato unito di TUTTI quattro tabelle nelle clausole FROM e USING.
Il " j.jobid " alias è solo il nome completo di una delle colonne in quella raccolta di tabelle unita.
In MySQL, è spesso interessante chiedere a Query Optimizer cosa intende fare, con:
EXPLAIN SELECT [...]
VEDI http://dev.mysql.com/doc/ refman / 5.0 / it / join.html
E inizia a leggere qui:
Partecipa all'elaborazione delle modifiche in MySQL 5.0.12
A partire da MySQL 5.0.12, i join naturali e i join con USING, comprese le varianti di join esterne, vengono elaborati secondo lo standard SQL: 2003. L'obiettivo era allineare la sintassi e la semantica di MySQL rispetto a NATURAL JOIN e JOIN ... USANDO secondo SQL: 2003. Tuttavia, queste modifiche nell'elaborazione dei join possono comportare colonne di output diverse per alcuni join. Inoltre, alcune query che sembrano funzionare correttamente nelle versioni precedenti devono essere riscritte per essere conformi allo standard.
Queste modifiche hanno cinque aspetti principali:
-
Il modo in cui MySQL determina le colonne dei risultati delle operazioni di join NATURAL o USING (e quindi il risultato dell'intera clausola FROM).
-
Espansione di SELECT * e SELECT tbl_name. * in un elenco di colonne selezionate.
-
Risoluzione dei nomi delle colonne nei join NATURAL o USING.
-
La trasformazione dei join NATURAL o USING in JOIN ... ON.
-
Risoluzione dei nomi di colonna nella condizione ON di un JOIN ... ON.
Non sono sicuro della parte ON vs USING (anche se questo website dice che sono uguali)
Per quanto riguarda la domanda di ordinazione, la sua specifica implementazione (e probabilmente la query). Molto probabilmente MYSQL prende un ordine durante la compilazione della richiesta. Se si desidera applicare un ordine particolare, è necessario "annidare" le query:
SELECT c.*
FROM companies AS c
JOIN (SELECT * FROM users AS u
JOIN (SELECT * FROM jobs AS j USING(userid)
JOIN useraccounts AS us USING(userid)
WHERE j.jobid = 123)
)
come per la parte 4: la clausola where limita le righe della tabella dei lavori a cui è possibile aderire. Quindi, se ci sono righe che si unirebbero a causa degli userid corrispondenti ma non hanno il jobid corretto, verranno omesse.
Ecco una risposta più dettagliata sulla precedenza JOIN
. Nel tuo caso, i JOIN
sono tutti commutativi. Proviamo uno dove non sono.
Crea schema:
CREATE TABLE users (
name text
);
CREATE TABLE orders (
order_id text,
user_name text
);
CREATE TABLE shipments (
order_id text,
fulfiller text
);
Aggiungi dati:
INSERT INTO users VALUES ('Bob'), ('Mary');
INSERT INTO orders VALUES ('order1', 'Bob');
INSERT INTO shipments VALUES ('order1', 'Fulfilling Mary');
Esegui query:
SELECT *
FROM users
LEFT OUTER JOIN orders
ON orders.user_name = users.name
JOIN shipments
ON shipments.order_id = orders.order_id
Risultato:
Viene restituita solo la riga Bob
Analisi:
In questa query il LEFT OUTER JOIN
è stato valutato per primo e il JOIN
è stato valutato sul risultato composito del LEFT OUTER JOIN
.
Seconda query:
SELECT *
FROM users
LEFT OUTER JOIN (
orders
JOIN shipments
ON shipments.order_id = orders.order_id)
ON orders.user_name = users.name
Risultato:
Una riga per Bob (con i dati di evasione) e una riga per Mary con NULL per i dati di evasione.
Analisi:
La parentesi ha cambiato l'ordine di valutazione.
Ulteriore documentazione di MySQL è disponibile all'indirizzo https: // dev.mysql.com/doc/refman/5.5/en/nested-join-optimization.html