Domanda

L'altro giorno ho imparato qualcosa di semplice su SQL:

SELECT c FROM myTbl GROUP BY C

Ha lo stesso risultato di:

SELECT DISTINCT C FROM myTbl

Ciò di cui sono curioso, c'è qualcosa di diverso nel modo in cui un motore SQL elabora il comando o sono davvero la stessa cosa?

Personalmente preferisco la sintassi distinta, ma sono sicuro che sia più per abitudine che altro.

EDIT: questa non è una domanda sugli aggregati. L'uso di GROUP BY con funzioni aggregate è compreso.

È stato utile?

Soluzione

MusiGenesis 'funzionalmente quello corretto per quanto riguarda la tua domanda come indicato; SQL Server è abbastanza intelligente da capire che se stai utilizzando " Raggruppa per " e non usando alcuna funzione aggregata, allora ciò che realmente intendi è "Distinto". - e quindi genera un piano di esecuzione come se avessi semplicemente usato " Distinto. "

Tuttavia, penso che sia importante notare Hank anche la risposta - trattamento sprezzante di " Raggruppa per " e "distinto" potrebbe portare ad alcuni dannosi trucchi se non stai attento. Non è del tutto corretto affermare che questa non è una domanda sugli aggregati. perché stai chiedendo la differenza funzionale tra due parole chiave di query SQL, una delle quali è pensata per essere utilizzata con gli aggregati e una delle quali no.

A volte un martello può funzionare per avvitare una vite, ma se hai un cacciavite a portata di mano, perché preoccuparsi?

(ai fini di questa analogia, Hammer: Screwdriver :: GroupBy: Distinct e screw = > ottieni un elenco di valori univoci in una colonna della tabella )

Altri suggerimenti

GROUP BY ti consente di utilizzare funzioni aggregate, come AVG , MAX , MIN , SUM e COUNT . D'altra parte DISTINCT rimuove solo i duplicati.

Ad esempio, se hai un sacco di record di acquisto e vuoi sapere quanto è stato speso da ciascun dipartimento, potresti fare qualcosa del tipo:

SELECT department, SUM(amount) FROM purchases GROUP BY department

Questo ti darà una riga per reparto, contenente il nome del reparto e la somma di tutti i valori importo in tutte le righe per quel dipartimento.

Usa DISTINCT se vuoi solo rimuovere i duplicati. Utilizzare GROUPY BY se si desidera applicare operatori aggregati ( MAX , SUM , GROUP_CONCAT , ... o una clausola HAVING .

Qual è la differenza da un semplice punto di vista della funzionalità di rimozione duplicata

A parte il fatto che, a differenza di DISTINCT , GROUP BY consente di aggregare i dati per gruppo (che è stato menzionato da molte altre risposte) , la differenza più importante secondo me è il fatto che le due operazioni "avvengono". in due passaggi molto diversi nella ordine logico delle operazioni eseguite in un'istruzione SELECT .

Ecco le operazioni più importanti:

  • FROM (compresi ISCRIVITI , APPLY , ecc.)
  • dove
  • GROUP BY (può rimuovere duplicati)
  • Le aggregazioni
  • CHE HA
  • Funzioni finestra
  • Selezionare
  • DISTINCT (può rimuovere duplicati)
  • UNION , INTERSECT , EXCEPT (può rimuovere duplicati)
  • ORDINA PER
  • OFFSET
  • LIMITE

Come puoi vedere, l'ordine logico di ogni operazione influenza ciò che può essere fatto con essa e come influenza le operazioni successive. In particolare, il fatto che l'operazione GROUP BY " avvenga prima di " l'operazione SELECT (la proiezione) significa che:

  1. Non dipende dalla proiezione (che può essere un vantaggio)
  2. Non può usare alcun valore dalla proiezione (che può essere uno svantaggio)

1. Non dipende dalla proiezione

Un esempio in cui non è utile dipendere dalla proiezione è se si desidera calcolare le funzioni della finestra su valori distinti:

SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film
GROUP BY rating

Quando eseguito contro il Database Sakila , questo produce:

rating   rn
-----------
G        1
NC-17    2
PG       3
PG-13    4
R        5

Lo stesso non si può ottenere facilmente con DISTINCT :

SELECT DISTINCT rating, row_number() OVER (ORDER BY rating) AS rn
FROM film

Quella query è " errata " e produce qualcosa del tipo:

rating   rn
------------
G        1
G        2
G        3
...
G        178
NC-17    179
NC-17    180
...

Questo non è quello che volevamo. L'operazione DISTINCT " avviene dopo " la proiezione, quindi non possiamo più rimuovere le classificazioni DISTINCT perché la funzione della finestra era già stata calcolata e proiettata. Per utilizzare DISTINCT , dovremmo nidificare quella parte della query:

SELECT rating, row_number() OVER (ORDER BY rating) AS rn
FROM (
  SELECT DISTINCT rating FROM film
) f

Nota a margine: In questo caso particolare, potremmo anche usare DENSE_RANK ()

SELECT DISTINCT rating, dense_rank() OVER (ORDER BY rating) AS rn
FROM film

2. Non può utilizzare alcun valore dalla proiezione

Uno degli svantaggi di SQL è la sua verbosità a volte. Per lo stesso motivo di quello che abbiamo visto prima (vale a dire l'ordine logico delle operazioni), non possiamo "facilmente". raggruppare per qualcosa che stiamo proiettando.

Questo è SQL non valido:

SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY name

Questo è valido (ripetendo l'espressione)

SELECT first_name || ' ' || last_name AS name
FROM customer
GROUP BY first_name || ' ' || last_name

Anche questo è valido (annidando l'espressione)

SELECT name
FROM (
  SELECT first_name || ' ' || last_name AS name
  FROM customer
) c
GROUP BY name

Ho scritto più approfonditamente su questo argomento in un post sul blog

Mi aspetto che ci sia la possibilità di sottili differenze nella loro esecuzione. Ho controllato i piani di esecuzione di due query funzionalmente equivalenti lungo queste linee in Oracle 10g:

core> select sta from zip group by sta;

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    58 |   174 |    44  (19)| 00:00:01 |
|   1 |  HASH GROUP BY     |      |    58 |   174 |    44  (19)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| ZIP  | 42303 |   123K|    38   (6)| 00:00:01 |
---------------------------------------------------------------------------

core> select distinct sta from zip;

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    58 |   174 |    44  (19)| 00:00:01 |
|   1 |  HASH UNIQUE       |      |    58 |   174 |    44  (19)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| ZIP  | 42303 |   123K|    38   (6)| 00:00:01 |
---------------------------------------------------------------------------

L'operazione centrale è leggermente diversa: "HASH GROUP BY " vs. "quot HASH UNIQUE", ma i costi stimati ecc. sono identici. Ho quindi eseguito questi con traccia su e il conteggio delle operazioni effettive era lo stesso per entrambi (tranne per il fatto che il secondo non doveva fare alcuna lettura fisica a causa della memorizzazione nella cache).

Ma penso che, poiché i nomi delle operazioni sono diversi, l'esecuzione seguirà percorsi di codice in qualche modo diversi e ciò apre la possibilità di differenze più significative.

Penso che dovresti preferire la sintassi DISTINCT per questo scopo. Non è solo un'abitudine, indica più chiaramente lo scopo della query.

Per la query che hai pubblicato, sono identici. Ma per altre query che potrebbero non essere vere.

Ad esempio, non è lo stesso di:

SELECT C FROM myTbl GROUP BY C, D

Ho letto tutti i commenti sopra ma non ho visto nessuno indicare la differenza principale tra Group By e Distinct a parte il bit di aggregazione.

Distinto restituisce tutte le righe, quindi le de-duplica, mentre Raggruppa de-deduplica le righe mentre vengono lette dall'algoritmo una per una.

Ciò significa che possono produrre risultati diversi!

Ad esempio, i codici seguenti generano risultati diversi:

SELECT distinct ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable

 SELECT ROW_NUMBER() OVER (ORDER BY Name), Name FROM NamesTable
GROUP BY Name

Se nella tabella ci sono 10 nomi in cui 1 è un duplicato di un altro, la prima query restituisce 10 righe mentre la seconda query restituisce 9 righe.

Il motivo è quello che ho detto sopra in modo che possano comportarsi diversamente!

Se si utilizza DISTINCT con più colonne, il set di risultati non verrà raggruppato come in GROUP BY e non è possibile utilizzare le funzioni aggregate con DISTINCT.

Hanno una semantica diversa, anche se hanno risultati equivalenti sui tuoi dati particolari.

GROUP BY ha un significato molto specifico che è distinto (eh) dalla funzione DISTINCT.

GROUP BY fa sì che i risultati della query vengano raggruppati utilizzando l'espressione scelta, è quindi possibile applicare funzioni di aggregazione, che agiranno su ciascun gruppo anziché sull'intero gruppo di risultati.

Ecco un esempio che potrebbe aiutare:

Data una tabella che assomiglia a questa:

name
------
barry
dave
bill
dave
dave
barry
john

Questa query:

SELECT name, count(*) AS count FROM table GROUP BY name;

Produrrà un output in questo modo:

name    count
-------------
barry   2
dave    3
bill    1
john    1

Che è ovviamente molto diverso dall'uso di DISTINCT. Se si desidera raggruppare i risultati, utilizzare GROUP BY, se si desidera solo un elenco univoco di una colonna specifica, utilizzare DISTINCT. Ciò darà al tuo database la possibilità di ottimizzare la query per le tue esigenze.

Per favore, non usare GROUP BY quando intendi DISTINCT, anche se funzionano allo stesso modo. Suppongo che tu stia cercando di radere millisecondi dalle query e devo sottolineare che il tempo degli sviluppatori è molto più costoso degli ordini di grandezza del tempo del computer.

Se si utilizza un GROUP BY senza alcuna funzione aggregata, internamente verrà trattato come DISTINCT, quindi in questo caso non vi è alcuna differenza tra GROUP BY e DISTINCT.

Ma quando ti viene fornita la clausola DISTINCT meglio usarla per trovare i tuoi record univoci perché l'obiettivo di GROUP BY è raggiungere l'aggregazione.

raggruppa per viene utilizzato in operazioni aggregate, ad esempio quando si desidera ottenere un conteggio di Bs suddiviso per colonna C

select C, count(B) from myTbl group by C

distinto è come suona: ottieni righe uniche.

In sql server 2005, sembra che Query Optimizer sia in grado di ottimizzare la differenza negli esempi semplicistici che ho eseguito. Non so se puoi contare su quello in tutte le situazioni, però.

In quella particolare query non c'è differenza. Ma, naturalmente, se aggiungi colonne aggregate, dovrai utilizzare group by.

Dal punto di vista di "SQL the language" i due costrutti sono equivalenti e quale si sceglie è una di quelle scelte di "stile di vita" che tutti noi dobbiamo fare. Penso che ci sia un buon caso per DISTINCT più esplicito (e quindi più attento alla persona che erediterà il tuo codice, ecc.), Ma ciò non significa che il costrutto GROUP BY sia una scelta non valida.

Penso che questo 'GROUP BY sia per aggregati' sia l'enfasi sbagliata. Le persone devono essere consapevoli del fatto che la funzione impostata (MAX, MIN, COUNT, ecc.) Può essere omessa in modo da poter comprendere l'intento del programmatore quando è.

L'ottimizzatore ideale riconoscerà costrutti SQL equivalenti e sceglierà sempre il piano ideale di conseguenza. Per il tuo vero motore SQL preferito, devi testare :)

PS nota che la posizione della parola chiave DISTINCT nella clausola select può produrre risultati diversi, ad es. contrasto:

SELECT COUNT(DISTINCT C) FROM myTbl;

SELECT DISTINCT COUNT(C) FROM myTbl;

Nella prospettiva di Teradata :

Dal punto di vista del set di risultati, non importa se si utilizza DISTINCT o GROUP BY in Teradata. Il set di risposte sarà lo stesso.

Dal punto di vista delle prestazioni, non è lo stesso.

Per capire cosa influisce sulle prestazioni, è necessario sapere cosa succede su Teradata quando si esegue una dichiarazione con DISTINCT o GROUP BY.

Nel caso di DISTINCT, le righe vengono ridistribuite immediatamente senza alcuna preaggregazione, mentre nel caso di GROUP BY, in una prima fase viene eseguita una preaggregazione e solo allora i valori univoci vengono ridistribuiti tra gli AMP.

Non pensare ora che GROUP BY sia sempre migliore dal punto di vista delle prestazioni. Quando si hanno molti valori diversi, la fase di preaggregazione di GROUP BY non è molto efficiente. Teradata deve ordinare i dati per rimuovere i duplicati. In questo caso, potrebbe essere meglio prima ridistribuire, ovvero usare l'istruzione DISTINCT. Solo se ci sono molti valori duplicati, l'istruzione GROUP BY è probabilmente la scelta migliore poiché solo una volta effettuata la fase di deduplicazione, dopo la ridistribuzione.

In breve, DISTINCT vs. GROUP BY a Teradata significa:

GROUP BY - > per molti duplicati DISTINCT - > no o solo pochi duplicati. A volte, quando si utilizza DISTINCT, si esaurisce lo spazio di spooling su un AMP. Il motivo è che la ridistribuzione ha luogo immediatamente e l'inclinazione potrebbe causare l'esaurimento degli AMP.

Se ciò accade, probabilmente hai una migliore possibilità con GROUP BY, poiché i duplicati vengono già rimossi in un primo passaggio e meno dati vengono spostati attraverso gli AMP.

Lo noti solo perché stai selezionando una singola colonna.

Prova a selezionare due campi e guarda cosa succede.

Raggruppa per deve essere utilizzato in questo modo:

SELECT name, SUM(transaction) FROM myTbl GROUP BY name

Che mostrerebbe la somma di tutte le transazioni per ogni persona.

So che è un vecchio post. Ma succede che avevo una query che utilizzava il gruppo solo per restituire valori distinti quando si utilizzava quella query in rospo e l'oracolo riporta che tutto ha funzionato bene, intendo un buon tempo di risposta. Quando abbiamo eseguito la migrazione da Oracle 9i a 11g, il tempo di risposta in Toad è stato eccellente, ma nel rapporto ci sono voluti circa 35 minuti per completare il rapporto quando si utilizzava la versione precedente, ci sono voluti circa 5 minuti.

La soluzione era cambiare il gruppo e usare DISTINCT e ora il rapporto viene eseguito in circa 30 secondi.

Spero che questo sia utile per qualcuno con la stessa situazione.

Il modo in cui l'ho sempre capito è che usare il distinto è lo stesso del raggruppamento per ogni campo selezionato nell'ordine in cui li hai selezionati.

cioè:

select distinct a, b, c from table;

è uguale a:

select a, b, c from table group by a, b, c

L'efficienza funzionale è totalmente diversa. Se desideri selezionare solo " valore di ritorno " tranne uno duplicato, usare distinguere è meglio che raggruppare per. Perché " raggruppa per " include (ordinamento + rimozione), "distinto" include (rimuovendo)

In Hive (HQL), raggruppare può essere molto più veloce di distinto, perché il primo non richiede il confronto di tutti i campi nella tabella. Vedi https://sqlperformance.com/2017 / 01 / t-SQL-interroga / sorprese-ipotesi-group-by-distinta .

Non vi è alcuna differenza significativa tra clausola group by e distinta tranne l'uso di funzioni aggregate. Entrambi possono essere utilizzati per distinguere i valori, ma se nel punto di vista delle prestazioni raggruppare è migliore. Quando viene utilizzata una parola chiave distinta, internamente utilizza un'operazione di ordinamento che può essere visualizzata nel piano di esecuzione.

Prova un semplice esempio

Dichiara la tabella @tmpresult (   Id tinyint )

Inserisci in @tmpresult Seleziona 5 Unione tutto Seleziona 2 Unione tutto Seleziona 3 Unione tutto Seleziona 4

Seleziona distinto Id Da @tmpresult

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top