C'è qualche differenza sostanziale tra le query unite dalle clausole WHERE e le query che utilizzano un JOIN effettivo?


32

In Learn SQL the Hard Way (esercizio sei) , l'autore presenta la seguente query:

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

e poi continua dicendo che:

Esistono in realtà altri modi per far funzionare questi tipi di query chiamate "join". Sto evitando questi concetti per ora perché sono follemente confusi. Atteniti a questo modo di unirti ai tavoli per ora e ignora le persone che cercano di dirti che questo è in qualche modo più lento o "di bassa classe".

È vero? Perché o perché no?


3
Non credo ci sia, ma potresti provare a fare un EXPLAIN per vedere se c'è qualche differenza nell'esecuzione della query.
GrandmasterB,

6
Vorrei sottolineare i segnali contrastanti di un'opera con "The Hard Way" nel titolo saltando un concetto "perché sono follemente confusi". Ma forse è solo il mio concetto di ciò che "il modo difficile" dovrebbe essere sbagliato. Ma di nuovo, forse no.
Mindwin,

7
JOIN trasporta molto bene l'intenzione (unire le tabelle), ciò lascia la parte WHERE per i filtri effettivi e ne semplifica la lettura. (Oltre a molte altre implicazioni)
Th 00 mÄ s

2
Stai imparando SQL nel modo più duro se l'autore non può preoccuparsi di scrivere semplici join! Come dice ThomasS usando JOIN, le intenzioni sono rese più chiare e le clausole WHERE diventano molto più semplici. Anche l'utilizzo di JOIN illustra meglio la teoria degli insiemi alla base di SQL.
Daniel Hollinrake,

1
Non sono sicuro di come mi sento riguardo a qualcosa che pretende di insegnarti qualcosa mentre dici "Ma hey salteremo questo concetto fondamentale perché sono banane craaazzzyyyy." Penso che finirei per cercare una fonte diversa da cui imparare. Ad un certo punto dovrai fare join esterni e cross join e dovresti sapere come eseguirli.
Maurice Reeves,

Risposte:


23

Con l'approccio dell'autore, insegnare OUTER JOINs sarà molto più difficile. La clausola ON di INNER JOIN non mi ha mai fatto impazzire come molte altre cose. Forse è perché non ho mai imparato alla vecchia maniera. Mi piacerebbe pensare che ci sia una ragione per cui ce ne siamo sbarazzati e non doveva essere compiaciuto e chiamare questo metodo di classe bassa.

È vero nello scenario molto ristretto che l'autore ha creato:

  • Tale entry level di SQL che l'utilizzo di ON è complesso
  • Considerando solo JOIN / INNER JOIN e non eventuali JOU ESTERNI
  • Il programmatore isolato che non deve leggere il codice altrui né avere persone con esperienza nell'uso di ON che legge / utilizza il proprio codice.
  • Non richiede query complesse con molte: tabelle, if's, ma's e o's.

Come parte di una progressione dell'insegnamento, penso che sia più facile scomporlo e avere una progressione naturale:

Select * from table
select this, something, that from table
select this from table where that = 'this'
select this from table join anothertable on this.id = that.thisid

I concetti di unione e filtro delle tabelle non sono realmente gli stessi. Imparare la sintassi corretta ora avrà più riporto quando si impara outer join a meno che l'autore intende sull'insegnamento obsoleti cose / deprecate come: *= or =*.


5
Il motivo per cui è stata aggiunta l'istruzione JOIN era perché non esisteva uno standard per esprimere i join esterni, quindi ogni fornitore di database aveva la propria sintassi "speciale" (incompatibile). IIRC Oracle aveva *=o =*indicava i join esterni sinistro o destro, un altro che ho usato supportava solo i join esterni sinistro usando un |=operatore.
TMN,

1
@TMN IIRC Oracle usato +=o forse lo era =+. Credo che *=fosse Transact-SQL (Sybase e successivamente MS-SQL). Comunque, buon punto.
David,

1
Il punto in cui inizia a complicarsi (IMHO) è quando hai un mix di join interno ed esterno. In quel tipo di situazione, confesserò che a volte ricado nella tecnica "di bassa classe" di eseguire i miei join nella WHEREclausola. (Ho sentito che si parla di theta join , ma non sono sicuro che sia corretto.)
David

Gli operatori IIRC come "maggiore di" o "uguale a" venivano talvolta indicati come "operatori theta", ma una ricerca su Google porta ad alcune operazioni di calcolo.
Walter Mitty,

12

Se è più lento dipende dallo Strumento per ottimizzare le query e da come semplifica la query (ciò che scrivi non è in realtà ciò che viene eseguito). Tuttavia, il grosso problema di questa citazione è che ignora completamente il fatto che ci sono diversi tipi di join che funzionano in modo completamente diverso. Ad esempio, ciò che viene detto è (teoricamente) vero per inner joins, ma non vale per outer joins( left joinse right joins).


9
+1 Per altri tipi di join. La maggior parte dei miei iscritti sono INNER JOINo LEFT OUTER JOIN. Non sono "follemente confusi". SQL può diventare follemente confuso, ma questo non ne è un esempio.
mgw854,

fuori tema, ma dovrebbe essere la dichiarazione diversi tipi di aderire s o tipi di aderire ?
user1451111

9

L'autore presenta un semplice caso in cui è possibile utilizzare la sintassi precedente o nuova. Non sono d'accordo sulla sua affermazione che i join sono follemente confusi, perché unire le tabelle è un concetto di query SQL fondamentale. Quindi, forse l'autore avrebbe dovuto dedicare un po 'di tempo prima a spiegare come funzionano i JOIN prima di pronunciare un'istruzione supponente e fare un esempio di query con più tabelle.

Si dovrebbe usare la sintassi più recente. L'argomento principale per questo è che la tua query avrà:

  • Seleziona i criteri
  • Unisciti ai criteri
  • Criteri di filtro

Utilizzando il vecchio stile, i criteri di join e filtro vengono combinati, il che in casi più complessi può creare confusione.

Inoltre, è possibile ottenere un prodotto cartesiano dimenticando un criterio di join nella clausola del filtro:

 person_pet.person_id = person.id

usando la sintassi precedente.

L'uso della sintassi più recente specifica anche come dovrebbe avvenire il join, il che è importante se si desidera un INNER, LEFT OUTER, ecc., Quindi è più esplicito per quanto riguarda la sintassi JOIN che IMHO aumenta la leggibilità per coloro che non hanno familiarità con le tabelle di join.


5

Non dovrebbe esserci, il parser di query dovrebbe generare una rappresentazione interna equivalente per query equivalenti indipendentemente da come sono scritte. L'autore sta solo usando la sintassi pre-SQL-92, motivo per cui afferma che potrebbe essere visto come "vecchio stile" o "bassa classe". Internamente, il parser e l'ottimizzatore dovrebbero generare lo stesso piano di query.


5

Ho imparato SQL in questo modo, inclusa la *=sintassi per i join esterni. Per me, è stato molto intuitivo poiché tutte le relazioni hanno avuto la stessa precedenza e ha svolto un lavoro migliore nell'impostare le query come una serie di domande: cosa vuoi? Da dove le vuoi? Quali vuoi?

Facendo la joinsintassi, interrompe il processo di pensiero verso le relazioni più fortemente. E personalmente trovo il codice molto meno leggibile con le tabelle e le relazioni mescolate.

Almeno in MSSQL, non c'è alcuna differenza significativa nelle prestazioni delle query, supponendo che tu usi lo stesso ordinamento di join. Detto questo, c'è un chiaro, enorme problema con l'apprendimento (e l'utilizzo) di SQL in questo modo. Se dimentichi una delle tue relazioni, otterrai prodotti incrociati inaspettati. Che su un database di qualsiasi dimensione non banale è proibitivamente costoso (e pericoloso per i non-seletti!). È molto più difficile dimenticare una relazione quando si utilizza la joinsintassi dello stile.


7
È un database relazionale , quindi le relazioni sono piuttosto importanti per una query. Personalmente trovo molto più difficile dare un senso a una query che mescola filtri veri (foo.x = 5) con relazioni (foo.x = bar.x). Il motore può facilmente ottimizzarlo in un join, ma essenzialmente un essere umano deve ragionare riga per riga, al contrario di insiemi e sottoinsiemi.
Aaronaught il

4

Esistono due aspetti diversi da considerare: prestazioni e manutenibilità / leggibilità .

Manutenibilità / Leggibilità

Ho scelto una query diversa, in quanto è qualcosa che penso sia un esempio migliore / peggiore della query originale che hai pubblicato.

Cosa ti sembra migliore ed è più leggibile?

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh
on e.BusinessEntityID = edh.BusinessEntityID
inner join HumanResources.Department d
on edh.DepartmentID = d.DepartmentID
where d.Name = 'Engineering';

O...

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e, 
HumanResources.EmployeeDepartmentHistory edh,
HumanResources.Department d
where e.BusinessEntityID = edh.BusinessEntityID
and edh.DepartmentID = d.DepartmentID
and d.Name = 'Engineering';

Per me personalmente, il primo è abbastanza leggibile. Vedete che stiamo unendo le tabelle INNER JOIN, il che significa che stiamo estraendo le righe corrispondenti alla successiva clausola di join (ovvero "unisciti a Employee con EmployeeDepartmentHistory su BusinessEntityID e includiamo quelle righe").

Quest'ultima, la virgola non significa nulla per me. Mi chiedo cosa stai facendo con tutti quei WHEREpredicati della clausola.

Il primo legge di più come pensa il mio cervello. Guardo SQL tutto il giorno ogni giorno e le virgole per i join. Il che mi porta al prossimo punto ...

Esistono in realtà altri modi per far funzionare questi tipi di query chiamate "join"

Sono tutti uniti. Anche le virgole sono un join. Il fatto che l'autore non li chiami è davvero la loro rovina ... non è ovvio. Dovrebbe essere ovvio. Stai unendo i dati relazionali, sia che tu specifichi JOINo ,.

Prestazione

Questo dipenderà sicuramente da RDBMS. Posso parlare solo per conto di Microsoft SQL Server. Per quanto riguarda le prestazioni, questi sono equivalenti. Come lo sai? Cattura i piani di post-esecuzione e guarda cosa sta facendo esattamente SQL Server per ciascuna di queste affermazioni:

inserisci qui la descrizione dell'immagine

Nell'immagine sopra, ho evidenziato che sto usando entrambe le query come sopra, differendo solo per i caratteri espliciti per il join ( JOINvs ,). SQL Server fa esattamente la stessa cosa.

Sommario

Non utilizzare le virgole. Usa JOINdichiarazioni esplicite .


Ho imparato INNER JOINs molto prima di rendermi conto che la variante con le clausole WHERE è equivalente ed entrambi i tuoi esempi mi sembrano molto leggibili. Quello con le WHERE e le virgole potrebbe essere ancora più leggibile. Dove cade, penso, si trova in query complesse, non queste relativamente semplici.
Robert Harvey,

Il punto è, pensare che la variazione di virgola non sia un join relazionale non è affatto corretta.
Thomas Stringer,

Penso che tu stia interpretando erroneamente le virgole come join. Le virgole si limitano a separare le tabelle; sono le condizioni DOVE che creano i join, non le virgole.
Robert Harvey,

1
Posso sicuramente affermare che non vi è alcun tipo di unione nelle clausole del predicato. Penso che tu stia interpretando erroneamente i costrutti della tua query relazionale. Hai provato a unire la tua virgola senza le clausole WHERE? Funziona ancora. È un join cartesiano. Cosa pensi di guadagnare usando le virgole? Per favore, non dire che stai cercando di salvare personaggi.
Thomas Stringer,

1
Direi che il primo è migliore perché le tue intenzioni sono più chiare. C'è molta meno ambiguità.
Daniel Hollinrake,

4

No, non è affatto vero. L'autore sta creando confusione nei suoi lettori e incoraggiando la programmazione cargo-cult che evita una differenza strutturale molto potente tra la sintassi standard e questa variante precedente che preferisce. In particolare, una clausola WHERE ingombra rende più difficile capire cosa rende speciale la sua query.

Il suo esempio porta un lettore a generare una mappa mentale del suo significato che ha un sacco di disordine.

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

All'incirca, quanto sopra è:

Ottieni l'ID dell'animale, NAME, AGE e DEAD per tutti gli animali domestici, person_pet e le persone in cui l'ID dell'animale corrisponde a un pet_id di un person_pet e l'identificativo person di quel record corrisponde al person_id di una persona il cui FIRST_NAME è "Zed"

Con una mappa mentale del genere, il lettore (che sta scrivendo l'SQL a mano per qualche motivo) può facilmente commettere un errore, possibilmente omettendo una o più tabelle. E un lettore di codice scritto in questo modo dovrà lavorare di più, per capire esattamente cosa sta cercando di fare l'autore SQL. ("Più difficile" è a livello di lettura di SQL con o senza l'evidenziazione della sintassi, ma è comunque una differenza maggiore di zero.)

C'è un motivo per cui i JOIN sono comuni, ed è il vecchio classico canard "separazione dei problemi". In particolare, per una query SQL c'è una buona ragione per separare come sono strutturati i dati rispetto a come vengono filtrati.

Se la query è stata scritta in modo più pulito, ad esempio

SELECT pet.id, pet.name, pet.age
FROM pet
  JOIN person_pet ON pet.id = person_pet.pet_id
  JOIN person ON person.id = person_pet.person_id
WHERE 
  person.first_name = "Zed";

Quindi il lettore ha una distinzione più chiara tra i componenti di ciò che viene richiesto. Il filtro distintivo di questa query è separato dal modo in cui i suoi componenti si relazionano tra loro e i componenti necessari di ogni relazione sono direttamente accanto al punto in cui sono richiesti.


Naturalmente, qualsiasi sistema di database moderno non dovrebbe vedere una differenza significativa tra i due stili. Ma se le prestazioni del database fossero l'unica considerazione, la query SQL non avrebbe nemmeno spazi bianchi o maiuscole.


2
Da quando ho sentito questo ritornello più volte, lasciami fare il difensore del diavolo. Impara X il modo difficile è avere profondità tecnica; chiunque abbia una buona conoscenza di SQL dovrebbe davvero sapere che i due approcci sono equivalenti, in termini di output che producono.
Robert Harvey,

1
Posso vederlo, ma l'autore non sta semplicemente affermando che sono dichiarazioni equivalenti a un server SQL decente; stanno affermando che l'uso di JOIN è "confuso", che è un percorso lungo il quale il codice sporco attende. ("No, non usare LINQ, basta scrivere a mano la tua dichiarazione FOR." "Il compilatore non si preoccupa di ciò che chiamo questo metodo, quindi non c'è motivo di non chiamarlo FN1")
DougM,

3

Guy sta facendo un classico errore. Sta cercando di insegnare un concetto astratto con un'implementazione specifica. Non appena lo fai, entri in questo tipo di casino.

Avrei dovuto insegnare prima i concetti di base del database, quindi mostrare SQL come un modo per descriverli.

I join destro e sinistro, si potrebbe sostenere che non contano troppo. Outer Join, beh, potresti usare old *=e la =*sintassi.

Ora potresti sostenere che la sintassi è più semplice, ma solo per query semplici. Non appena inizi a provare a eseguire una query complessa con questa versione, puoi avere un disastro orribile. La "nuova" sintassi non è stata introdotta in modo da poter eseguire query complesse, è stato quindi eseguire query complesse in modo leggibile e quindi gestibile.


3
"Learn X in the Hard Way" è un approccio di apprendimento diverso. Scrivi il codice e poi lo capisci in seguito.
Robert Harvey,

7
@RobertHarvey Questo non è un approccio di apprendimento diverso, è quello standard. Successivamente si verifica solo se ti capita di essere ancora in posizione quando le ruote si staccano. affrontato troppe persone che scrivono SQL che pensano che una tabella sia una matrice rettangolare di celle per avere fiducia in questo metodo.
Tony Hopkinson,

2

L'esempio è equivalente alla semplice riformulazione con JOIN interni. La differenza sta solo nelle possibilità aggiuntive che la sintassi JOIN consente. Ad esempio, è possibile specificare l'ordine in cui vengono elaborate le colonne delle due tabelle interessate; vedi ad esempio https://stackoverflow.com/a/1018825/259310 .

La saggezza ricevuta è, in caso di dubbio, scrivere le tue domande in modo da renderle più leggibili. Ma se le formulazioni JOIN o WHERE siano più facili da leggere sembra essere una questione di preferenza personale, motivo per cui entrambe le forme sono così diffuse.


Buona risposta, anche se si utilizza WHEREo si inserisce la clausola JOINnell'istruzione può effettivamente avere un impatto sulle prestazioni a seconda dello Strumento per ottimizzare le query. L'ho visto succedere più di una volta.
Locke,

La mia esperienza con l'impatto sulle prestazioni è questa: i join impliciti consentiranno a Query Optimizer più opzioni per ottimizzare la query, che può sembrare una buona cosa, ma può essere un problema. In particolare, Query Optimizer può ottimizzare la query in un modo nello sviluppo e in un altro in produzione. L'ottimizzatore può essere ingannato nell'ottimizzazione che riduce le prestazioni. La mia raccomandazione è di usare la sintassi esplicita del join E confermare che il join sta usando colonne che hanno indici in modo tale che le prestazioni siano prevedibili.
Michael Potter,

2

Quando ho imparato SQL, i moduli INNER JOIN, LEFT JOIN, ecc. Non esistevano. Come hanno già affermato altre risposte, diversi dialetti di SQL avevano implementato join esterni usando una sintassi idiosincratica. Questa portabilità danneggiata del codice SQL. Riunire la lingua ha richiesto qualche cambiamento, e LEFT JOIN, ecc. È stato quello su cui si sono stabiliti.

È vero che per ogni INNER JOIN è possibile scrivere una virgola equivalente con la condizione di join nella clausola WHERE. Mi ci è voluto un po 'di tempo per migrare dal gradimento della vecchia forma alla preferenza della nuova forma. Apparentemente, l'autore di Learning SQL the Hard Way pensa ancora che il vecchio modo sia più semplice.

Ci sono differenze? Bene, sì, ci sono. Il primo è che un INNER JOIN con una clausola ON rivela l'intento dell'autore più chiaramente del vecchio stile. Il fatto che la clausola ON sia in effetti una condizione di join e non un altro tipo di restrizione è più evidente. Questo rende il codice che utilizza INNER JOIN più facile da imparare durante la lettura rispetto al vecchio stile. Questo è importante quando si mantiene il codice di qualcun altro.

La seconda differenza è che il nuovo stile rende leggermente più semplice per Query Optimizer scoprire la strategia vincente. Questo è un effetto molto piccolo, ma è reale.

La terza differenza è che quando impari a usare INNER JOIN (o semplicemente JOIN semplice), è più facile imparare LEFT JOIN, ecc.

A parte questo, non vi è alcuna differenza materiale.


0

Dipende se pensi in termini di set e logica formale .....

Se non si utilizza la parola chiave "join" si ottiene una progressione più semplice dalla logica formale a SQL.

Ma se come il 99% delle persone, non ti è piaciuta la logica formale nella tua laurea in matematica, allora la parola chiave join è più facile da imparare. SQL veniva presentato all'università come un altro modo per scrivere domande logiche formali ...

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.