MySQLではSELECT DISTINCTまたはGROUP BYのどちらが速いですか?


273

テーブルがあれば

CREATE TABLE users (
  id int(10) unsigned NOT NULL auto_increment,
  name varchar(255) NOT NULL,
  profession varchar(255) NOT NULL,
  employer varchar(255) NOT NULL,
  PRIMARY KEY  (id)
)

そして、私はprofessionフィールドのすべての一意の値を取得したいのですが、何が速くなりますか(または推奨されます):

SELECT DISTINCT u.profession FROM users u

または

SELECT u.profession FROM users u GROUP BY u.profession


2
質問するのと同じくらい早く自分でテストできます。苛立たしいことに、DISTINCTがGROUP BYよりも優れているシナリオを構築することはほとんど不可能です。これは明らかにGROUP BYの目的ではないため、これは厄介です。ただし、GROUP BYは誤解を招く結果を生成する可能性があるため、これを回避するのに十分な理由だと思います。
イチゴ

別の答えを持つ別の重複があります。MySqlを参照してください
-Distinct

クエリを実行するDISTINCTとGROUP BYの時間差を測定する場合は、こちらをご覧ください。
kolunar

回答:


258

それらは基本的に互いに同等です(実際、これは一部のデータベースが内部DISTINCTで実装する方法です)。

それらの1つがより速い場合、それはなるでしょうDISTINCT。これは、2つは同じですが、クエリオプティマイザーがGROUP BYグループメンバーを利用しておらず、キーだけを利用しているという事実を把握する必要があるためです。DISTINCTこれを明示的にするので、少し気味の悪いオプティマイザで回避できます。

疑わしいときはテストしてください!


76
DISTINCTは、インデックスがない場合にのみ高速になります(ソートされないため)。インデックスがあり、それが使用されている場合、それらは同義語です。
Quassnoi、2009

10
の定義DISTINCTGROUP BY違いはDISTINCT、出力をソートする必要がなくGROUP BY、デフォルトでそうです。しかし、MySQLの中でも、DISTINCT+がORDER BYあります、まだ速くよりもGROUP BYSquareCogで説明したようにオプティマイザのために余分なヒントが原因。
rustyx 2015年

1
DISTINCTは、大量のデータを使用するとはるかに高速になります。
Pankaj Wanjari

7
私はこれをテストしましたが、インデックスが付けられた列mysqlでは、group byは、かなり複雑なクエリを使用した場合と比べて、約6倍遅いことがわかりました。これをデータポイントとして追加するだけです。約10万行。だからそれをテストし、自分の目で確かめてください。
Lizardx 2016

MySqlを参照してください
-Distinct

100

にインデックスがある場合profession、これら2つは同義語です。

そうでない場合は、を使用してくださいDISTINCT

GROUP BYMySQL結果をソートします。あなたも行うことができます:

SELECT u.profession FROM users u GROUP BY u.profession DESC

そして、あなたの職業をDESC順番に並べ替えます。

DISTINCT一時テーブルを作成し、それを複製の保存に使用します。GROUP BY同じことを行いますが、後で異なる結果を並べ替えます。

そう

SELECT DISTINCT u.profession FROM users u

にインデックスがない場合は、より高速ですprofession


6
に追加ORDER BY NULLしてGROUP BY、ソートを回避できます。
アリエル

nullによるグループ化を使用してもさらに遅い
Thanh Trung

@ThanhTrung:何が何より遅いですか?
Quassnoi

@Quassnoi groupbyはソートを回避しても明確よりも遅い
Thanh Trung

注:GROUP BYで注文予選は、MySQL 8で非推奨
マシュー・レンツ

18

上記のすべての答えは正しいです。単一列のDISTINCTと単一列のGROUP BYの場合です。すべてのdbエンジンには独自の実装と最適化があり、ごくわずかな違い(ほとんどの場合)を気にする場合は、特定のサーバーおよび特定のバージョンに対してテストする必要があります。実装が変更される可能性があるため...

ただし、クエリで複数の列を選択した場合、DISTINCTは本質的に異なります。この場合、1つの列だけではなく、すべての行のすべての列を比較するためです。

したがって、次のようなものがある場合:

// This will NOT return unique by [id], but unique by (id,name)
SELECT DISTINCT id, name FROM some_query_with_joins

// This will select unique by [id].
SELECT id, name FROM some_query_with_joins GROUP BY id

DISTINCTキーワードは指定した最初の列によって行を区別すると考えるのはよくある間違いですが、DISTINCTはこのように一般的なキーワードです。

したがって、上記の答えをすべてのケースに当てはまらないように注意する必要がある人々...最適化することだけが目的であると、混乱して間違った結果が得られる可能性があります。


3
この質問 MySQL に関するものですが、2番目のクエリはMySQLでのみ機能することに注意してください。2番目のステートメントはGROUP BY演算子の無効な使用であるため、他のほぼすべてのDBMSでは2番目のステートメントが拒否されます。
a_horse_with_no_name 2013

まあ、「ほぼ」は問題のある定義です:-) このステートメントに対してエラーを生成することを確認するためにテストした特定のDBMSを述べると、はるかに役立ちます。
daniel.gindi 2013

3
初心者向けのPostgres、Oracle、Firebird、DB2、SQL Server。MySQL:sqlfiddle.com / #!2 / 6897c/1 Postgres:sqlfiddle.com / #!12 / 6897c/1 Oracle:sqlfiddle.com / #!12 / 6897c/1 SQL Server:sqlfiddle.com
a_horse_with_no_name 2013

17

可能な場合は、最も単純で最短の方法を使用してください。DISTINCTは、必要な答えを正確に提供するためだけに、探しているもののようです。


7

Group byは、Distinctよりも高価です。これは、Group Byが結果をソートする一方で、distinctがそれを回避するためです。しかし、group byを作成したい場合は、nullによる個別の順序付けと同じ結果が得られます

SELECT DISTINCT u.profession FROM users u

等しい

SELECT u.profession FROM users u GROUP BY u.profession order by null

等しいSELECT profession FROM users GROUP BY profession

6

postgresでは、明確に区別することがグループ化よりも遅くなる場合があります(他のデータベースについては知らない)。

テスト済みの例:

postgres=# select count(*) from (select distinct i from g) a;

count 

10001
(1 row)

Time: 1563,109 ms

postgres=# select count(*) from (select i from g group by i) a;

count
10001
(1 row)

Time: 594,481 ms

http://www.pgsql.cz/index.php/PostgreSQL_SQL_Tricks_I

ので注意してください ... :)


5

クエリはまったく同じではないようです。少なくともMySQLでは。

比較:

  1. northwind.productsから特定の製品名を選択してください
  2. Northwind.productsグループから選択した製品名を製品名で説明する

2番目のクエリは、Extraで「filesortの使用」を追加します。


1
彼らは何を得るかという点ではなく、何を得るかという点では同じです。理想的なオプティマイザは同じ方法でそれらを実行しますが、MySQLオプティマイザは理想的ではありません。あなたの証拠に基づくと、DISTINCTの方が速くなるようです-O(n)対O(n * log n)。
SquareCog、2009

それで、「filesortを使用する」ことは本質的に悪いことですか?
ヴァバ

この場合は、並べ替える必要がないためです(グループが必要な場合は並べ替えます)。MySQLは同じエントリを一緒に配置するためにソートし、ソートされたファイルをスキャンしてグループを取得します。一意が必要なだけなので、単一のテーブルスキャンを実行するときにキーをハッシュする必要があります。
SquareCog、2009

1
追加ORDER BY NULLGROUP BYバージョンと、彼らは同じになります。
アリエル

3

MySQLの、「Group By」余分なステップを使用していますfilesort。がにDISTINCT比べて速いことに気付きGROUP BY、それは驚きでした。


3

厳しいテストの後、GROUP BYの方が速いという結論に達しました

SELECT sql_no_cache opnamegroep_intern FROM telwerken WHERE opnemergroepIN(7,8,9,10,11,12,13)group by opnamegroep_intern

635トータル0.0944秒Weergave vanは0〜29を記録します(635トータル、クエリデュルド0.0484秒)

sql_no_cacheを個別に選択(opnamegroep_intern)FROM telwerken WHERE opnemergroepIN(7,8,9,10,11,12,13)

635トータル0.2117秒(ほぼ100%遅い)Weergaveバンの記録0-29(635トータル、クエリデュアード0.3468秒)


2

(機能メモの詳細)

GROUP BYを使用する必要がある場合があります。たとえば、雇用者ごとの従業員数を取得する場合などです。

SELECT u.employer, COUNT(u.id) AS "total employees" FROM users u GROUP BY u.employer

このようなシナリオでDISTINCT u.employerは正しく機能しません。たぶん方法はあるかもしれませんが、私はそれを知りません。(誰かがDISTINCTでそのようなクエリを行う方法を知っている場合は、メモを追加してください!)


2

以下は、クエリごとに2つの異なる経過時間を出力する簡単な方法です。

DECLARE @t1 DATETIME;
DECLARE @t2 DATETIME;

SET @t1 = GETDATE();
SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT
SET @t2 = GETDATE();
PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar);

SET @t1 = GETDATE();
SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY
SET @t2 = GETDATE();
PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar);

またはSET STATISTICS TIMEを試してください(Transact-SQL)

SET STATISTICS TIME ON;
SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT
SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY
SET STATISTICS TIME OFF;

以下のように、各ステートメントの解析、コンパイル、および実行に必要なミリ秒数を表示します。

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 2 ms.

1

これはルールではありません

各クエリについて....個別に試し、次にグループ化...各クエリを完了するまでの時間を比較して、より高速な...を使用します。

私のプロジェクトでは、いつかグループバイと他のグループを区別して使用します


0

グループ関数(テーブルに数値データを追加する場合の合計、平均など)を実行する必要がない場合は、SELECT DISTINCTを使用します。私はそれがより速いと思うが、私はそれを示すものは何もない。

いずれにしても、速度が心配な場合は、列にインデックスを作成してください。


0

SELECT DISTINCTは、常にGROUP BYよりも同じか、または速くなります。一部のシステム(Oracleなど)では、ほとんどのクエリでDISTINCTと同じになるように最適化される場合があります。他のもの(SQL Serverなど)では、かなり高速になる可能性があります。


0

問題がそれを許す場合は、結果が見つかるとすぐに終了するように最適化されている(そして応答をバッファリングしない)ため、EXISTSを試してください。したがって、このようなWHERE句のデータを正規化しようとしている場合

SELECT FROM SOMETHING S WHERE S.ID IN ( SELECT DISTINCT DCR.SOMETHING_ID FROM DIFF_CARDINALITY_RELATIONSHIP DCR ) -- to keep same cardinality

より速い応答は:

SELECT FROM SOMETHING S WHERE EXISTS ( SELECT 1 FROM DIFF_CARDINALITY_RELATIONSHIP DCR WHERE DCR.SOMETHING_ID = S.ID )

これは常に可能であるとは限りませんが、可能な場合はより速い応答が表示されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.