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

32

In Impara SQL in modo difficile (esercizio 6) , 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:

There are actually other ways to get these kinds of queries to work called "joins". I'm avoiding those concepts for now because they are insanely confusing. Just stick to this way of joining tables for now and ignore people who try to tell [you] that this is somehow slower or "low class".

È vero? Perché o perché no?

    
posta Robert Harvey 15.01.2015 - 19:23
fonte

11 risposte

23

Con l'approccio dell'autore, insegnare OUTER JOINs sarà molto più difficile. La clausola ON di INNER JOIN non mi è mai sembrata sconvolgente come molte altre cose. Forse è perché non ho mai imparato il vecchio modo. Mi piacerebbe pensare che ci sia una ragione per cui ci siamo sbarazzati di esso e non era di essere compiaciuto e chiamare questo metodo di classe bassa.

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

  • Un tale entry level di SQL che utilizza ON è complesso
  • Solo considerando JOIN / INNER JOIN e non OUTER JOINs
  • Il coder isolato che non deve leggere il codice di altri né avere persone con esperienza nell'uso di ON leggendo / utilizzando il loro codice.
  • Non richiede query complesse con molte: tabelle, if, ma's e o's.

Come parte di una progressione nell'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 filtraggio delle tabelle non sono esattamente gli stessi. Imparare la sintassi corretta ora avrà più carry over quando impari OUTER JOINS a meno che l'autore non intenda insegnare cose obsolete / deprecate come: *= or =* .

    
risposta data 15.01.2015 - 20:03
fonte
12

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

    
risposta data 15.01.2015 - 19:48
fonte
9

L'autore presenta un caso semplice in cui è possibile utilizzare la sintassi vecchia o nuova. Non sono d'accordo sulla sua affermazione che i join sono follemente confusionari, 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 le JOIN funzionassero prima di pronunciare una dichiarazione motivata e facendo un esempio di query su più tabelle.

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

  • Seleziona criteri
  • Criteri di adesione
  • Criteri di filtro

Usando il vecchio stile, vengono combinati i criteri di join e di filtro che nei casi più complessi possono creare confusione.

Inoltre, si può ottenere un prodotto cartesiano dimenticando un criterio di join nella clausola del filtro:

 person_pet.person_id = person.id

usando la sintassi più vecchia.

L'uso della sintassi più recente specifica anche come dovrebbe verificarsi il join, importante se si desidera un INTERNO, un LEUTERO SINISTRO, ecc. quindi è più esplicito riguardo alla sintassi JOIN che IMHO aumenta la leggibilità per coloro che non hanno familiarità con le tabelle di join.

    
risposta data 15.01.2015 - 22:46
fonte
5

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

    
risposta data 15.01.2015 - 20:00
fonte
5

Ho imparato SQL in questo modo, inclusa la sintassi *= per i join esterni. Per me è stato molto intuitivo poiché a tutte le relazioni è stata data uguale priorità e ha fatto un lavoro migliore di impostare le domande come una serie di domande: cosa vuoi? Da dove li vuoi? Quali vuoi?

Eseguendo la sintassi join , interrompe il processo di pensiero verso le relazioni in modo più strong. E personalmente, trovo il codice molto meno leggibile con le tabelle e le relazioni intrecciate.

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

    
risposta data 15.01.2015 - 22:39
fonte
4

Ci sono due aspetti diversi da considerare: Prestazioni e Manutenibilità / Readability .

Maintainability / leggibilità

Ho scelto una query diversa, in quanto è qualcosa che ritengo 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';

Oppure ...

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 con INNER JOIN , il che significa che stiamo tirando le righe che corrispondono alla successiva clausola join (ad esempio "unire EmployeeDepartmentHistory su BusinessEntityID e includere quelle righe").

Quest'ultimo, la virgola non significa niente per me. Mi viene da chiedersi cosa si sta facendo con tutti quei predicati della clausola WHERE .

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

There are actually other ways to get these kinds of queries to work called "joins"

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 JOIN o , .

Prestazioni

Questo sarà sicuramente dipendente 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 scopri cosa sta facendo esattamente SQL Server per ognuna di queste affermazioni:

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

Sommario

Non usare virgole. Utilizza le istruzioni esplicite JOIN .

    
risposta data 19.01.2015 - 00:13
fonte
4

No, non è affatto vero. L'autore sta preparando i suoi lettori per la confusione e incoraggiando la programmazione settoriale del carico che evita una differenza strutturale molto potente tra la sintassi standard e questa variante più vecchia che preferisce. In particolare, una clausola WHERE disordinata 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 confusione.

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";

Approssimativamente, quanto sopra è:

Get the pet's ID, NAME, AGE, and DEAD for all pets, person_pet, and persons where the pet ID happens to match a person_pet's pet_id, and the person_id of that record happens to match the person_id of a person whose FIRST_NAME is "Zed"

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

C'è una ragione per cui le JOIN sono comuni, ed è il classico classico "seperazione delle preoccupazioni" canard. In particolare, per una query SQL ci sono buone ragioni per separare il modo in cui i dati sono strutturati rispetto a come vengono filtrati i dati.

Se la query è scritta più pulita, come

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 chiara distinzione tra le componenti di ciò che viene richiesto. Il filtro distintivo di questa query è separato dal modo in cui i componenti si correlano tra loro e i componenti necessari di ogni relazione sono direttamente accanto a dove sono richiesti.

Naturalmente, qualsiasi sistema di database moderno non dovrebbe vedere una differenza significativa tra i due stili. Ma se la prestazione del database fosse l'unica considerazione, la query SQL non avrebbe spazio bianco o maiuscole,

    
risposta data 16.01.2015 - 22:50
fonte
3

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

Avrebbe dovuto insegnare prima i concetti di base del database, poi ha mostrato SQL come un modo per descriverli.

Join destro e sinistro, si potrebbe sostenere che non hanno importanza. Outer Join, beh potresti usare la vecchia sintassi *= e =* .

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

    
risposta data 15.01.2015 - 19:55
fonte
2

L'esempio è equivalente alla semplice riformulazione con inner JOIN. La differenza sta unicamente nelle possibilità aggiuntive consentite dalla sintassi JOIN. Ad esempio, è possibile specificare l'ordine in cui vengono elaborate le colonne delle due tabelle interessate; vedere per es. link .

La saggezza ricevuta è, nel dubbio, di scrivere le tue domande nel modo che le rende più leggibili. Ma se le formulazioni JOIN o WHERE sono più facili da leggere sembra essere una questione di preferenze personali, motivo per cui entrambe le forme sono così diffuse.

    
risposta data 15.01.2015 - 19:53
fonte
2

Quando ho imparato SQL, i moduli INNER JOIN, LEFT JOIN, ecc. non esistevano. Come altre risposte hanno già affermato, diversi dialetti di SQL hanno implementato tutti i join esterni usando la sintassi idiosincratica. Questa portabilità danneggiata del codice SQL. Riportare la lingua insieme richiedeva alcuni cambiamenti e LEFT JOIN, ecc. Era quello su cui si erano 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 'per passare dal gradire la vecchia forma a preferire la nuova forma. Apparentemente, l'autore di Learning SQL the Hard Way pensa ancora che la vecchia maniera sia più facile.

Ci sono delle differenze? Bene, sì, ci sono. Il primo è che un INNER JOIN con una clausola ON rivela le intenzioni dell'autore più chiaramente rispetto al vecchio stile join. Il fatto che la clausola ON sia in effetti una condizione di join e non un altro tipo di restrizione è più ovvia. Questo rende il codice che usa 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ù facile 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), diventa più facile imparare LEFT JOIN, ecc.

A parte questo non c'è alcuna differenza sostanziale.

    
risposta data 31.01.2015 - 21:05
fonte
0

Dipende se pensi in termini di insiemi 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 piace la logica formale in matematica, allora la parola chiave join è più facile da imparare. SQL veniva presentato all'università come un altro modo per scrivere query logiche formali ....

    
risposta data 06.06.2015 - 16:49
fonte

Leggi altre domande sui tag