テーブルがある場合
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
?
これらは本質的に互いに同等です(実際、これは一部のデータベースが内部でDISTINCT
を実装する方法です)。
それらのいずれかが高速である場合、それはDISTINCT
になります。これは、2つは同じですが、クエリオプティマイザーは、GROUP BY
がグループメンバーではなくキーだけを利用しているという事実をキャッチする必要があるためです。 DISTINCT
はこれを明示的にするので、少しダンバーなオプティマイザーで逃げることができます。
疑わしい場合は、テストしてください!
profession
にインデックスがある場合、これら2つは同義語です。
そうでない場合は、DISTINCT
を使用します。
MySQL
のGROUP BY
は結果をソートします。あなたもすることができます:
SELECT u.profession FROM users u GROUP BY u.profession DESC
職業をDESC
の順に並べ替えます。
DISTINCT
は、一時テーブルを作成し、それを使用して重複を保存します。 GROUP BY
は同じことをしますが、後で個別の結果をソートします。
そう
SELECT DISTINCT u.profession FROM users u
profession
にインデックスがない場合は高速です。
可能な場合は、最もシンプルで短いものを探してください。DISTINCTは、必要な答えを正確に提供するという理由だけで、あなたが探しているものよりも多いようです。
単一の列での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はこの方法では一般的なキーワードです。
したがって、すべての場合に上記の答えを正しいものとして受け取らないように注意する必要があります...最適化するだけで混乱し、間違った結果を得る可能性があります!
明確に区別することは、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
ので注意してください ... :)
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
クエリはまったく同じではないようです。少なくともMySQLの場合。
比較:
2番目のクエリは、Extraでさらに「filesortを使用」を提供します。
MySQLでは、「Group By
」は追加のステップfilesort
を使用します。 DISTINCT
はGROUP BY
よりも高速であることに気付きました。
以下は、クエリごとに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.
(機能的なメモの詳細)
雇用主ごとの従業員数を取得する場合など、GROUP BYを使用する必要がある場合があります。
SELECT u.employer, COUNT(u.id) AS "total employees" FROM users u GROUP BY u.employer
このようなシナリオでは、DISTINCT u.employer
は正しく機能しません。おそらく方法がありますが、私はそれを知りません。 (DISTINCTを使用してこのようなクエリを作成する方法を誰かが知っている場合は、メモを追加してください!)
徹底的なテストの後、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)
グループ関数(テーブルに数値データを追加する場合の合計、平均など)を行う必要がない場合は、SELECT DISTINCTを使用します。私はそれが速いと思うが、私はそれのために何も見せない。
いずれにせよ、速度が心配な場合は、列にインデックスを作成してください。
これはルールではありません
各クエリについて....個別に個別に試行し、次にグループ化...各クエリを完了する時間を比較し、より高速な...を使用します。
私のプロジェクトでは、group byと他の異なる
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 )
これは常に可能とは限りませんが、利用可能な場合は、より速い応答が表示されます。
SELECT DISTINCTは常にGROUP BYと同じか、または高速です。一部のシステム(Oracleなど)では、ほとんどのクエリでDISTINCTと同じになるように最適化される場合があります。その他(SQL Serverなど)では、かなり高速になります。