私は2つのテーブルInstitutionsとResultsを持っています。そして、結果のないものを除外できる方法で、機関の結果があるかどうかを確認したいと思います。
JOINまたはEXISTSを使用してパフォーマンスを向上させることはできますか?
ありがとうございました、
-ニメシュ
ステートメント、統計、DBサーバーによっては、違いがない場合もあります。同じ最適化されたクエリプランが作成される場合があります。
基本的に、DBが内部でテーブルを結合する方法は3つあります。
ネストされたループ-1つのテーブルが2番目のテーブルよりもはるかに大きい場合。小さいテーブルのすべての行が、大きいテーブルのすべての行に対してチェックされます。
マージ-同じソート順の2つのテーブル。どちらも順番に実行され、対応する場所で照合されます。
ハッシュ-その他すべて。一時テーブルは、一致を構築するために使用されます。
Existsを使用することにより、クエリプランにネストされたループを強制的に実行させることができます。これが最も速い方法かもしれませんが、実際にはクエリプランナーが決定する必要があります。
両方のSQLステートメントを記述してクエリプランを比較する必要があると思います。持っているデータによっては、かなり変化することがあります。
たとえば、[機関]と[結果]のサイズが類似していて、両方がInstitutionIDでクラスター化されている場合、マージ結合が最も速くなります。 [結果]が[機関]よりもはるかに大きい場合、ネストされたループの方が速い場合があります。
場合によります。
最終的に、2つはまったく異なる目的で使用されます。
2つのテーブルを結合して、関連するレコードにアクセスします。関連するレコードのデータにアクセスする必要がない場合は、それらを結合する必要はありません。
EXISTSは、特定のデータセットにトークンが存在するかどうかを判断するために使用できますが、関連するレコードにアクセスすることはできません。
あなたが考えている2つの方法の例を投稿してください。そうすれば、私はあなたにより良いアイデアを与えることができるかもしれません。
2つのテーブルInstitutionsとResultsを使用して、結果を持つ機関のリストが必要な場合、このクエリが最も効率的です。
select Institutions.institution_name
from Institutions
inner join Results on (Institutions.institution_id = Results.institution_id)
Institution_idがあり、それが結果を持っているかどうかだけを知りたい場合は、EXISTSを使用した方が速い場合があります。
if exists(select 1 from Results where institution_id = 2)
print "institution_id 2 has results"
else
print "institution_id 2 does not have results"
オプティマイザによって異なります。 Oracle 10gと11gで以下の2つを試しました。 10gでは、2番目の方がわずかに高速でした。 11gでは、それらは同一でした。
ただし、#1は実際にはEXISTS句の誤用です。結合を使用して一致を検索します。
select *
from
table_one t1
where exists (
select *
from table_two t2
where t2.id_field = t1.id_field
)
order by t1.id_field desc
select t1.*
from
table_one t1
,table_two t2
where t1.id_field = t2.id_field
order by t1.id_field desc
パフォーマンスに違いがあるかどうかにかかわらず、目的に適したものを使用する必要があります。機関のリストを取得することが目的です(結果ではありません-追加のデータは必要ありません)。そのため、結果がない機関を選択します...翻訳-EXISTSを使用します。
クエリの実行はEXISTS呼び出しが何かを見つけるとすぐに停止し、JOINは最後まで続くため、JOINの方が遅いと思います。
編集:しかし、それはクエリに依存します。これはケースバイケースで判断されるべきものです。
EXISTSを相関サブクエリの一部として使用していますか?その場合、結合はほとんど常に高速になります。
データベースには、クエリをベンチマークする方法が必要です。それらを使用して、どのクエリがより速く実行されるかを確認します。
LEFT OUTER JOINはNOT EXISTS **よりもパフォーマンスが向上する傾向がありますが、あなたの場合、EXISTSを実行する必要があり、単純なINNER JOINを使用してもEXISTSの動作が正確に複製されません。機関に複数の結果がある場合、INNER JOINを実行すると、その機関の複数の行が返されます。 DISTINCTを使用することで回避できますが、EXISTSの方がおそらくパフォーマンスが優れています。
**この方法に慣れていない場合:
SELECT
MyTable.MyTableID
FROM
dbo.MyTable T1
LEFT OUTER JOIN dbo.MyOtherTable T2 ON
T2.MyTableID = T1.MyTableID
WHERE
T2.MyOtherTableID IS NULL
に相当
SELECT
MyTable.MyTableID
FROM
dbo.MyTable T1
WHERE NOT EXISTS (SELECT * FROM MyOtherTable T2 WHERE T2.MyTableID = T1.MyTableID)
myOtherTableIDがNOT NULL列であると想定しています。最初の方法は通常、NOT EXISTSメソッドよりも高速に実行されます。
上記のような場合、Existsステートメントは、Joinよりも高速に機能します。 Existsは単一のレコードを提供し、時間も節約します。結合の場合、レコードの数は多くなり、すべてのレコードを使用する必要があります。
RESULTSテーブルにINSTITUTION
ごとに複数の行がある場合、EXISTS()
には、別個の機関を選択する必要がないという追加の利点があります。
パフォーマンスに関しては、さまざまな用途でjoins, IN(), and EXISTS()
がそれぞれ最速であることがわかりました。目的に最適な方法を見つけるには、テストする必要があります。
実際、問題の漠然とした説明から、NOT INクエリがコードを記述する最も明白な方法であるように思えます。
SELECT *
FROM Institutions
WHERE InstitutionID NOT IN (
SELECT DISTINCT InstitutionID
FROM Results
)
結果のない機関が必要な場合は、「Where Not Exists」サブクエリが高速になります。これは、結果のある機関の単一の結果が見つかるとすぐに停止するためです...
機関で結果を出したいが、実際には結果を望んでいない場合も同じです。 「存在する場所」サブクエリを使用します。単一の結果が見つかるとすぐに停止します...これにより、機関ごとに1つのレコードのみが結果セットに含まれることも保証されます。結合アプローチでは、 'distinct'キーワードまたは 'Group By'句を追加して、単一のシチュエーションに一致する複数の結果レコードから生成される重複するカーテション製品行を排除する必要があります。
結果が必要な場合は、JOIN-結果なしの機関を表示したくない場合は内部結合を実行し、結果のない機関を含むすべての機関を表示したい場合は外部結合を実行します。
左側(または右側)の外部結合を使用している場合、またはサブクエリが存在しない場合は、左側の外部結合の方がパフォーマンスの点で優れていると思います。例えば:
SELECT t1.* FROM table1 t1 LEFT OUTER JOIN table2 t2 ON t1.id = t2.id WHERE t2.id IS NULL
上記は同等のサブクエリよりも速く、存在を具体的に参照している場合は-構造が許せば、内部結合が常に推奨されるオプションになります。