先日、SQLについて簡単なことを学びました。
SELECT c FROM myTbl GROUP BY C
次と同じ結果になります。
SELECT DISTINCT C FROM myTbl
私が興味を持っているのは、SQLエンジンがコマンドを処理する方法に何か違いがありますか、それとも本当に同じものですか?
個人的には明確な構文を好みますが、それは他の何よりも習慣から外れていると確信しています。
編集:これは集計に関する質問ではありません。集約関数でのGROUP BY
の使用は理解されています。
MusiGenesis '応答は、記載されている質問に関して機能的に正しいものです。 SQL Serverは、「グループ化」を使用し、集計関数を使用しない場合、実際には「個別」を意味することを認識するほどスマートです。したがって、単に「個別」を使用したかのように実行プランを生成します」
ただし、 Hank の応答にも注意することが重要だと思います-「Group By」と「Distinct」を無頓着に扱うと、注意を怠ると有害な落とし穴が生じる可能性があります。これが「集計に関する質問ではない」と言うのは完全に正しいわけではありません。なぜなら、2つのSQLクエリキーワードの機能の違いについて尋ねているからです。その1つはおよびその1つはそうではありません。
ハンマーは時々ネジを打ち込むことができますが、ドライバーが手元にある場合は、なぜ気にしますか?
(この類推のために、Hammer : Screwdriver :: GroupBy : Distinct
とscrew => get list of unique values in a table column
)
GROUP BY
を使用すると、AVG
、MAX
、MIN
、SUM
、COUNT
などの集約関数を使用できます。一方、DISTINCT
は重複を削除するだけです。
たとえば、大量の購入記録があり、各部門がどのくらい費やしたかを知りたい場合、次のようにします。
SELECT department, SUM(amount) FROM purchases GROUP BY department
これにより、部門名と、その部門のすべての行のamount
値の合計を含む、部門ごとに1行が表示されます。
違いはありません(少なくともSQL Serverでは)。両方のクエリは同じ実行プランを使用します。
http://sqlmag.com/database-performance-tuning/distinct-vs-group
サブクエリが含まれている場合、is違いがあるかもしれません:
違いはありません(Oracleスタイル):
http://asktom.Oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212
重複を削除するだけの場合は、DISTINCT
を使用します。集約演算子(MAX
、SUM
、GROUPY BY
、...、またはHAVING
句)を適用する場合は、GROUP_CONCAT
を使用します。
DISTINCT
とは異なり、GROUP BY
はグループごとにデータを集約できる(他の多くの回答で言及されています)、私の最も重要な違い意見は、2つの操作が SELECT
ステートメントで実行される操作の論理的な順序 の2つの非常に異なるステップで「発生する」という事実です。
最も重要な操作は次のとおりです。
FROM
(JOIN
、APPLY
などを含む)WHERE
GROUP BY
(重複を削除できます)HAVING
SELECT
DISTINCT
(重複を削除できます)UNION
、INTERSECT
、EXCEPT
(重複を削除できます)ORDER BY
OFFSET
LIMIT
ご覧のとおり、各操作の論理的な順序は、各操作で実行できることと、後続の操作にどのように影響するかに影響します。特に、GROUP BY
操作「前に発生する」SELECT
操作(投影)は、次のことを意味します。
投影に依存しないことが有用な例は、異なる値のウィンドウ関数を計算する場合です。
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
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
実行に微妙な違いが生じる可能性があると思います。 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構文を好むと思います。これは単なる習慣ではなく、クエリの目的をより明確に示しています。
投稿したクエリの場合、それらは同じです。しかし、そうでないかもしれない他のクエリに対しては。
たとえば、次とは異なります。
SELECT C FROM myTbl GROUP BY C, D
上記のすべてのコメントを読みましたが、集計ビットを除き、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行を返します。
その理由は、私が上で言ったことなので、彼らは異なった振る舞いをすることができます!
DISTINCTを複数の列で使用する場合、結果セットはGROUP BYのようにグループ化されず、DISTINCTで集計関数を使用することはできません。
特定のデータに対して同等の結果が得られた場合でも、それらは異なるセマンティクスを持ちます。
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を使用します。これにより、データベースでニーズに合わせてクエリを最適化できます。
DISTINCTを意味する場合、たとえ同じように機能する場合でも、GROUP BYを使用しないでください。クエリのミリ秒を削減しようとしていると仮定していますが、開発者の時間はコンピューターの時間よりも桁違いに高いことを指摘する必要があります。
集約関数なしでGROUP BYを使用している場合、内部的にはDISTINCTとして扱われるため、この場合はGROUP BYとDISTINCTに違いはありません。
ただし、GROUP BYの目的は集約を達成することであるため、DISTINCT句を使用して一意のレコードを検索する方が適切です。
group byは集約操作で使用されます-列Cで分類されたBの数を取得する場合など
select C, count(B) from myTbl group by C
はっきりと見えるのは、ユニークな行です。
SQL Server 2005では、クエリオプティマイザーは、実行した単純な例の違いを最適化することができます。しかし、あらゆる状況でそれを当てにすることができればダンノ。
その特定のクエリでは違いはありません。ただし、もちろん、集計列を追加する場合は、group byを使用する必要があります。
結果セットの観点からは、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を使用する可能性が高くなります。
「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;
私はそれが古い投稿であることを知っています。しかし、ヒキガエルでそのクエリを使用するときに個別の値を返すためだけにgroup byを使用するクエリがあり、Oracleはすべてが正常に動作したことを報告します。つまり、良い応答時間を意味します。 Oracle 9iから11gに移行したとき、Toadの応答時間は優れていましたが、レポートでは、以前のバージョンを使用してレポートを完了するのに約35分かかりました。
解決策は、DISTINCTを使用してグループを変更し、レポートを約30秒で実行することでした。
これが同じ状況の人に役立つことを願っています。
気づいているのは、単一の列を選択しているためです。
2つのフィールドを選択して、何が起こるかを確認してください。
Group Byは、次のように使用することを目的としています。
SELECT name, SUM(transaction) FROM myTbl GROUP BY name
これは、各個人のすべてのトランザクションの合計を示します。
機能効率はまったく異なります。重複するものを除く「戻り値」のみを選択する場合は、group byよりもdistinctを使用することをお勧めします。 「グループ化」には(ソート+削除)が含まれるため、「個別」には(削除)が含まれます。
同じ結果が得られる場合もありますが、異なる意味/ケースで使用することを意図しています。主な違いは構文にあります。
以下の例をよく確認してください。 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
通常、DISTINCT
を使用して、テーブルの特定の列の重複を排除できます。
「GROUP BY」の場合、特定の列に
AVG
、MAX
、MIN
、SUM
、およびCOUNT
などの集約関数を適用して、列名とit集計関数の結果は同じ列になります。
例:
select specialColumn,sum(specialColumn) from yourTableName group by specialColumn;
Hive(HQL)では、group byは個別よりもずっと高速です。前者はテーブル内のすべてのフィールドを比較する必要がないためです。 https://sqlperformance.com/2017/01/t-sql-queries/surprises-assumptions-group-by-distinct を参照してください。
以前にこの質問がありました。400万行のテーブルから3つの列を追加する必要があります(3つの列を新しいテーブルの1つの新しい列に追加します)が、異なる列のみです。
そこで、このクエリを含むストアドプロシージャを 'group by'メソッドで実行しましたが、32分かかりました。その後、もう一度実行しましたが、「明確な」方法で25分かかりました。
同じ結果ですが、2番目の方法では少し速くなりました
私がいつも理解していた方法は、distinctを使用することは、選択したすべてのフィールドを選択した順序でグループ化することと同じことです。
すなわち:
select distinct a, b, c from table;
以下と同じです:
select a, b, c from table group by a, b, c