web-dev-qa-db-ja.com

MySQLのSELECT DISTINCTまたはGROUP BYの方が高速ですか?

テーブルがある場合

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

257
vava

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

それらのいずれかが高速である場合、それはDISTINCTになります。これは、2つは同じですが、クエリオプティマイザーは、GROUP BYがグループメンバーではなくキーだけを利用しているという事実をキャッチする必要があるためです。 DISTINCTはこれを明示的にするので、少しダンバーなオプティマイザーで逃げることができます。

疑わしい場合は、テストしてください!

236
SquareCog

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

そうでない場合は、DISTINCTを使用します。

MySQLGROUP BYは結果をソートします。あなたもすることができます:

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

職業をDESCの順に並べ替えます。

DISTINCTは、一時テーブルを作成し、それを使用して重複を保存します。 GROUP BYは同じことをしますが、後で個別の結果をソートします。

そう

SELECT DISTINCT u.profession FROM users u

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

98
Quassnoi

可能な場合は、最もシンプルで短いものを探してください。DISTINCTは、必要な答えを正確に提供するという理由だけで、あなたが探しているものよりも多いようです。

17
Tim

単一の列での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はこの方法では一般的なキーワードです。

したがって、すべての場合に上記の答えを正しいものとして受け取らないように注意する必要があります...最適化するだけで混乱し、間違った結果を得る可能性があります!

15
daniel.gindi

明確に区別することは、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

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

7
OptilabWorker

Group byは結果に対して並べ替えを行いますが、distinctは回避するため、Group byはDistinctよりも高価です。ただし、個別のグループと同じ結果を生成する場合は、order by null ..

SELECT DISTINCT u.profession FROM users u

等しい

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

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

比較:

  1. northwind.productsから特定の製品名を選択して説明する
  2. 製品名ごとにnorthwind.productsグループから選択した製品名を記述します

2番目のクエリは、Extraでさらに「filesortを使用」を提供します。

5
amartynov

MySQLでは、「Group By」は追加のステップfilesortを使用します。 DISTINCTGROUP BYよりも高速であることに気付きました。

3
Carlos

以下は、クエリごとに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);

または 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.
2
kolunar

(機能的なメモの詳細)

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

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

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

2
Ivan Dossev

徹底的なテストの後、GROUP BYの方が高速であるという結論に達しました

SELECT sql_no_cache opnamegroep_intern FROM telwerken WHERE opnemergroep IN(7,8,9,10,11,12,13)グループby opnamegroep_intern

635 totaal 0.0944秒Weergave van records 0-29(635 totaal、query duurde 0.0484 sec)

SELECT sql_no_cache distinct(opnamegroep_intern)FROM telwerken WHERE opnemergroep IN(7,8,9,10,11,12,13)

635 totaal 0.2117秒(ほぼ100%遅い)Weergave van records 0-29(635 totaal、query duurde 0.3468 sec)

1
Grumpy

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

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

1
tehvan

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

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

私のプロジェクトでは、group byと他の異なる

1
user2832991

If問題が許す場合、結果が見つかるとすぐに終了するように最適化されている(そして応答をバッファリングしない)ため、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 )

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

0
Daniel R

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

0
Beep beep