web-dev-qa-db-ja.com

GROUP BYとDISTINCTに違いはありますか

先日、SQLについて簡単なことを学びました。

SELECT c FROM myTbl GROUP BY C

次と同じ結果になります。

SELECT DISTINCT C FROM myTbl

私が興味を持っているのは、SQLエンジンがコマンドを処理する方法に何か違いがありますか、それとも本当に同じものですか?

個人的には明確な構文を好みますが、それは他の何よりも習慣から外れていると確信しています。

編集:これは集計に関する質問ではありません。集約関数でのGROUP BYの使用は理解されています。

273
Brettski

MusiGenesis '応答は、記載されている質問に関して機能的に正しいものです。 SQL Serverは、「グループ化」を使用し、集計関数を使用しない場合、実際には「個別」を意味することを認識するほどスマートです。したがって、単に「個別」を使用したかのように実行プランを生成します」

ただし、 Hank の応答にも注意することが重要だと思います-「Group By」と「Distinct」を無頓着に扱うと、注意を怠ると有害な落とし穴が生じる可能性があります。これが「集計に関する質問ではない」と言うのは完全に正しいわけではありません。なぜなら、2つのSQLクエリキーワードの機能の違いについて尋ねているからです。その1つはおよびその1つはそうではありません。

ハンマーは時々ネジを打ち込むことができますが、ドライバーが手元にある場合は、なぜ気にしますか?

(この類推のために、Hammer : Screwdriver :: GroupBy : Distinctscrew => get list of unique values in a table column

212
Skeolan

GROUP BYを使用すると、AVGMAXMINSUMCOUNTなどの集約関数を使用できます。一方、DISTINCTは重複を削除するだけです。

たとえば、大量の購入記録があり、各部門がどのくらい費やしたかを知りたい場合、次のようにします。

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

これにより、部門名と、その部門のすべての行のamount値の合計を含む、部門ごとに1行が表示されます。

127
Andru Luvisi

違いはありません(少なくともSQL Serverでは)。両方のクエリは同じ実行プランを使用します。

http://sqlmag.com/database-performance-tuning/distinct-vs-group

サブクエリが含まれている場合、is違いがあるかもしれません:

http://blog.sqlauthority.com/2007/03/29/sql-server-difference-between-distinct-and-group-by-distinct-vs-group-by/

違いはありません(Oracleスタイル):

http://asktom.Oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212

39
MusiGenesis

重複を削除するだけの場合は、DISTINCTを使用します。集約演算子(MAXSUMGROUPY BY、...、またはHAVING句)を適用する場合は、GROUP_CONCATを使用します。

31
jkramer

単なる重複削除機能の観点との違いは何ですか

DISTINCTとは異なり、GROUP BYはグループごとにデータを集約できる(他の多くの回答で言及されています)、私の最も重要な違い意見は、2つの操作が SELECTステートメントで実行される操作の論理的な順序 の2つの非常に異なるステップで「発生する」という事実です。

最も重要な操作は次のとおりです。

  • FROMJOINAPPLYなどを含む)
  • WHERE
  • GROUP BY(重複を削除できます)
  • 集計
  • HAVING
  • ウィンドウ関数
  • SELECT
  • DISTINCT(重複を削除できます)
  • UNIONINTERSECTEXCEPT(重複を削除できます)
  • ORDER BY
  • OFFSET
  • LIMIT

ご覧のとおり、各操作の論理的な順序は、各操作で実行できることと、後続の操作にどのように影響するかに影響します。特に、GROUP BY操作「前に発生する」SELECT操作(投影)は、次のことを意味します。

  1. 投影に依存しません(これは利点になる可能性があります)
  2. 投影からの値を使用できません(これはデメリットになる可能性があります)

1.投影に依存しません

投影に依存しないことが有用な例は、異なる値のウィンドウ関数を計算する場合です。

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

Sakilaデータベース に対して実行すると、次の結果が得られます。

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

DISTINCTでは簡単に同じことができませんでした:

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

そのクエリは「間違った」もので、次のような結果になります。

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

これは私たちが望んでいたものではありません。 DISTINCT操作 "投影の後に"が発生します。そのため、ウィンドウ関数は既に計算され投影されているため、DISTINCT評価を削除できません。 DISTINCTを使用するには、クエリのその部分をネストする必要があります。

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

補足: この特定のケースでは、DENSE_RANK()も使用できます

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

2.プロジェクションの値を使用できません

SQLの欠点の1つは、冗長であることです。前に見たのと同じ理由(つまり、操作の論理的な順序)のために、投影しているものによって「簡単に」グループ化することはできません。

これは無効なSQLです。

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

これは有効です(式を繰り返します)

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

これも有効です(式をネストする)

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

このトピックについてはブログ投稿で詳しく説明しました

27
Lukas Eder

実行に微妙な違いが生じる可能性があると思います。 Oracle 10gのこれらの行に沿って、機能的に同等の2つのクエリの実行計画を確認しました。

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

中間の操作は少し異なります:「HASH GROUP BY」と「HASH UNIQUE」ですが、推定コストなどは同じです。次に、トレースをオンにしてこれらを実行しましたが、実際の操作カウントは両方で同じでした(ただし、2番目のキャッシュはキャッシュのために物理的な読み取りを行う必要はありませんでした)。

しかし、操作名が異なるため、実行は多少異なるコードパスをたどり、より大きな違いが生じる可能性があると思います。

この目的にはDISTINCT構文を好むと思います。これは単なる習慣ではなく、クエリの目的をより明確に示しています。

19
Dave Costa

投稿したクエリの場合、それらは同じです。しかし、そうでないかもしれない他のクエリに対しては。

たとえば、次とは異なります。

SELECT C FROM myTbl GROUP BY C, D
14
Joel Coehoorn

上記のすべてのコメントを読みましたが、集計ビットを除き、Group ByとDistinctの主な違いを指摘している人はいませんでした。

Distinctはすべての行を返し、それらを重複排除しますが、Group Byはアルゴリズムによって1行ずつ読み取られるときに行を重複排除します。

これは、異なる結果を生成できることを意味します!

たとえば、次のコードは異なる結果を生成します。

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

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

テーブルに名前が10個あり、そのうちの1つが別の名前と重複している場合、最初のクエリは10行を返し、2番目のクエリは9行を返します。

その理由は、私が上で言ったことなので、彼らは異なった振る舞いをすることができます!

13
The Light

DISTINCTを複数の列で使用する場合、結果セットはGROUP BYのようにグループ化されず、DISTINCTで集計関数を使用することはできません。

12
Bill the Lizard

特定のデータに対して同等の結果が得られた場合でも、それらは異なるセマンティクスを持ちます。

11
Hank Gay

GROUP BYには、DISTINCT関数とは別個の(heh)非常に具体的な意味があります。

GROUP BYを使用すると、選択した式を使用してクエリ結果がグループ化され、集計関数を適用できます。これらは結果セット全体ではなく、各グループに作用します。

以下に役立つ例を示します。

次のようなテーブルがあるとします。

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

このクエリ:

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

次のような出力が生成されます。

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

これは、DISTINCTを使用した場合と明らかに大きく異なります。結果をグループ化する場合はGROUP BYを使用し、特定の列の一意のリストのみが必要な場合はDISTINCTを使用します。これにより、データベースでニーズに合わせてクエリを最適化できます。

5
Dan

DISTINCTを意味する場合、たとえ同じように機能する場合でも、GROUP BYを使用しないでください。クエリのミリ秒を削減しようとしていると仮定していますが、開発者の時間はコンピューターの時間よりも桁違いに高いことを指摘する必要があります。

5
Andy Lester

集約関数なしでGROUP BYを使用している場合、内部的にはDISTINCTとして扱われるため、この場合はGROUP BYとDISTINCTに違いはありません。

ただし、GROUP BYの目的は集約を達成することであるため、DISTINCT句を使用して一意のレコードを検索する方が適切です。

5

group byは集約操作で使用されます-列Cで分類されたBの数を取得する場合など

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

はっきりと見えるのは、ユニークな行です。

SQL Server 2005では、クエリオプティマイザーは、実行した単純な例の違いを最適化することができます。しかし、あらゆる状況でそれを当てにすることができればダンノ。

4
Danimal

その特定のクエリでは違いはありません。ただし、もちろん、集計列を追加する場合は、group byを使用する必要があります。

3

Teradataパースペクティブ

結果セットの観点からは、TeradataでDISTINCTまたはGROUP BYを使用するかどうかは関係ありません。回答セットは同じになります。

パフォーマンスの観点からは、同じではありません。

パフォーマンスに影響を与えるものを理解するには、DISTINCTまたはGROUP BYを使用してステートメントを実行するときにTeradataで何が起こるかを知る必要があります。

DISTINCTの場合、事前集計は行われずに行がすぐに再配布されますが、GROUP BYの場合、最初のステップで事前集計が実行され、一意の値がAMP全体に再配布されます。

GROUP BYがパフォーマンスの観点から常に優れているとは思わないでください。多くの異なる値がある場合、GROUP BYの事前集計手順はあまり効率的ではありません。 Teradataは、重複を削除するためにデータをソートする必要があります。この場合、最初に再配布することをお勧めします。つまり、DISTINCTステートメントを使用します。重複する値が多数ある場合のみ、再配布後に重複排除手順が実行されると、GROUP BYステートメントがおそらくより適切な選択になります。

つまり、TeradataのDISTINCTとGROUP BYの意味は次のとおりです。

GROUP BY->多数の重複の場合DISTINCT->重複なし、または少数の重複のみ。 DISTINCTを使用するときに、AMPのスプールスペースが不足することがあります。その理由は、再配布がすぐに行われ、スキューが原因でAMPのスペースが不足する可能性があるためです。

これが発生した場合、重複はすでに最初のステップで削除され、AMP間で移動されるデータが少なくなるため、GROUP BYを使用する可能性が高くなります。

2
Ram Ghadiyaram

「SQL the language」の観点からは、2つの構成要素は同等であり、どちらを選択するかは、私たちがしなければならない「ライフスタイル」選択の1つです。 DISTINCTがより明示的である(したがって、コードなどを継承する人により配慮される)場合は良いケースがあると思いますが、GROUP BY構文が無効な選択であることを意味するものではありません。

この「GROUP BYは集計のためです」は間違った強調だと思います。フォークは、セット関数(MAX、MIN、COUNTなど)を省略できるため、コーダーの意図を理解できるようにする必要があります。

理想的なオプティマイザーは同等のSQL構造を認識し、常にそれに応じて理想的なプランを選択します。選択した実際のSQLエンジンについては、テストする必要があります:)

PSは、select句のDISTINCTキーワードの位置が異なる結果を生成する場合があることに注意してください。コントラスト:

SELECT COUNT(DISTINCT C) FROM myTbl;

SELECT DISTINCT COUNT(C) FROM myTbl;
2
onedaywhen

私はそれが古い投稿であることを知っています。しかし、ヒキガエルでそのクエリを使用するときに個別の値を返すためだけにgroup byを使用するクエリがあり、Oracleはすべてが正常に動作したことを報告します。つまり、良い応答時間を意味します。 Oracle 9iから11gに移行したとき、Toadの応答時間は優れていましたが、レポートでは、以前のバージョンを使用してレポートを完了するのに約35分かかりました。

解決策は、DISTINCTを使用してグループを変更し、レポートを約30秒で実行することでした。

これが同じ状況の人に役立つことを願っています。

1
Gabriel

気づいているのは、単一の列を選択しているためです。

2つのフィールドを選択して、何が起こるかを確認してください。

Group Byは、次のように使用することを目的としています。

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

これは、各個人のすべてのトランザクションの合計を示します。

1
Chris Cudmore

機能効率はまったく異なります。重複するものを除く「戻り値」のみを選択する場合は、group byよりもdistinctを使用することをお勧めします。 「グループ化」には(ソート+削除)が含まれるため、「個別」には(削除)が含まれます。

0
Jun

同じ結果が得られる場合もありますが、異なる意味/ケースで使用することを意図しています。主な違いは構文にあります。

以下の例をよく確認してください。 DISTINCTは、値の重複セットを除外するために使用されます。 (6、cs、9.1)と(1、cs、5.5)は2つの異なるセットです。したがって、DISTINCTは両方の行を表示し、GROUP BY Branchは1つのセットのみを表示します。

 SELECT * FROM student; 
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    3 | civil  |  7.2 |
|    2 | mech   |  6.3 |
|    6 | cs     |  9.1 |
|    4 | eee    |  8.2 |
|    1 | cs     |  5.5 |
+------+--------+------+
5 rows in set (0.001 sec)

SELECT DISTINCT * FROM student; 
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    3 | civil  |  7.2 |
|    2 | mech   |  6.3 |
|    6 | cs     |  9.1 |
|    4 | eee    |  8.2 |
|    1 | cs     |  5.5 |
+------+--------+------+
5 rows in set (0.001 sec)

SELECT * FROM student GROUP BY Branch;
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    3 | civil  |  7.2 |
|    6 | cs     |  9.1 |
|    4 | eee    |  8.2 |
|    2 | mech   |  6.3 |
+------+--------+------+
4 rows in set (0.001 sec)

GROUP BY句で達成できる結果は、追加の句または条件を使用しないとDISTINCTで達成できない場合があります。例:上記の場合。

DISTINCTと同じ結果を得るには、以下のようなGROUP BY句ですべての列名を渡す必要があります。構文上の違いをご覧ください。その場合にGROUP BY句を使用するには、すべての列名に関する知識が必要です。

SELECT * FROM student GROUP BY Id, Branch, CGPA;
+------+--------+------+
| Id   | Branch | CGPA |
+------+--------+------+
|    1 | cs     |  5.5 |
|    2 | mech   |  6.3 |
|    3 | civil  |  7.2 |
|    4 | eee    |  8.2 |
|    6 | cs     |  9.1 |
+------+--------+------+

また、GROUP BYはデフォルトで昇順で結果を表示しますが、DISTINCTは表示しません。しかし、これについてはわかりません。ベンダーごとに異なる場合があります。

ソース: https://dbjpanda.me/dbms/languages/sql/sql-syntax-with-examples#group-by

0
SkyRar

通常、DISTINCTを使用して、テーブルの特定の列の重複を排除できます。

「GROUP BY」の場合、特定の列にAVGMAXMINSUM、およびCOUNTなどの集約関数を適用して、列名とit集計関数の結果は同じ列になります。

例:

select  specialColumn,sum(specialColumn) from yourTableName group by specialColumn;
0
Lova Chittumuri

Hive(HQL)では、group byは個別よりもずっと高速です。前者はテーブル内のすべてのフィールドを比較する必要がないためです。 https://sqlperformance.com/2017/01/t-sql-queries/surprises-assumptions-group-by-distinct を参照してください。

0
John Jiang

以前にこの質問がありました。400万行のテーブルから3つの列を追加する必要があります(3つの列を新しいテーブルの1つの新しい列に追加します)が、異なる列のみです。

そこで、このクエリを含むストアドプロシージャを 'group by'メソッドで実行しましたが、32分かかりました。その後、もう一度実行しましたが、「明確な」方法で25分かかりました。

同じ結果ですが、2番目の方法では少し速くなりました

0
Pedro Ivan

私がいつも理解していた方法は、distinctを使用することは、選択したすべてのフィールドを選択した順序でグループ化することと同じことです。

すなわち:

select distinct a, b, c from table;

以下と同じです:

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