2009-09-12 9 views
49

2つのテーブルの間に1対1の関係があります。私は、このクエリを使用して、テーブルBに対応する行を持たないテーブルAのすべての行を見つけたい:別のテーブルに対応する行がない行を1つのテーブルで見つける方法

SELECT id 
    FROM tableA 
WHERE id NOT IN (SELECT id 
        FROM tableB) 
ORDER BY id desc 

IDは、両方のテーブルの主キーです。プライマリキーインデックスとは別に、私はtableA(id desc)のインデックスも持っています。

H2(Java埋め込みデータベース)を使用すると、tableBのフルテーブルスキャンが実行されます。私は完全なテーブルスキャンを避けたい。

このクエリをすばやく実行するには、どのように書き直すことができますか?どのインデックスをすべきですか?

+1

[WHERE col [NOT] IN(SELECT col FROM othertable) 'を書くたびに、[NOT] EXISTSを使用してリファクタリングする方がよいでしょう。 – topchef

答えて

72
select tableA.id from tableA left outer join tableB on (tableA.id = tableB.id) 
where tableB.id is null 
order by tableA.id desc 

あなたのDBは、インデックスの交差点を行う方法を知っている場合、これが唯一の、時にはそれがleft joinよりも高速だので、主キーのインデックスが

+4

これは私がスタックオーバーフローを愛する理由です。土曜日、SQLの問題 - 質問は5分で正確に成功しました! –

+2

あなたは他の回答にもいくつか良い提案があります。当然私は私が最速になると思う:-)しかし、DBの実装は大きく異なり、私はH2についての経験はありません。さまざまなアプローチをベンチマークし、その結果を質問に反映させることは素晴らしいことです。 – SquareCog

25

あなたはまた、existsを使用することができます触れます。どちらを使いたいのかを判断するには、そのベンチマークを行う必要があります。総サブツリーのコスト -

left join:1.09724:

left joinexistsleft joinが、ここではこれらのクエリの実行計画は、SQL Server 2008でのものより、より効率的な場合がありますことを示すために

select 
    id 
from 
    tableA a 
where 
    not exists 
    (select 1 from tableB b where b.id = a.id) 

exists - 合計サブツリーコスト:1.074 21:

exists

+1

+1:EXISTS条件は、サブクエリ(このケースでは互換性があります)が少なくとも1つの行を返す場合、「満たす」とみなされます。 –

+0

ベンチマークは良い考えです。私は、dbが索引のみのハッシュ結合よりも速くなる存在+相関サブクエリのためにカバーの下で何をすることができるのか把握しようとしている私の頭を悩ましています。あなたは知っていますか? – SquareCog

+2

'Exists'は標準相関サブクエリを使用していません。セミジョインを使用します。 'left join'のためのSQL Server 2008の実行計画は、selectへのフィルタへのハッシュ一致に対する2つのインデックススキャンです。 「存在しない」の場合、選択なしフィルタへのハッシュ一致に対する2つのインデックススキャンである。 'exists'ハッシュマッチは実際には' left join'より少し速いです。 'left join'の総費用は1.09で、' AdventureWorksDW'から 'AdventureWorksDW2008'への' DimCustomer'には1.07の 'not exists'があります。 – Eric

3

私はH2(あるいはそれらのすべてが動作する場合)で最高となり、これらの方法のどれを伝えることはできませんが、私は(良い)のすべてを詳細に記事を書きましたTSQLで利用可能なメソッド。あなたは彼らに打撃を与えると、それらのいずれかがあなたのために動作するかどうかを確認することができます:あなたはTABLEB内のすべてのIDに対してにtableA内のすべてのIDをチェックする必要が

http://code.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=QueryBasedUponAbsenceOfData&referringTitle=Home

5

。フル機能のRDBMS(Oracleなど)は、これをINDEX FULL FAST SCANに最適化し、テーブルにはまったく触れることができません。 H2のオプティマイザがそれほどスマートであるかどうかはわかりません。

H2は、あなたがより速く実行することがあり、この

select id from tableA 
minus 
select id from tableB 
order by id desc 

を試す必要がありますので、MINUS構文をサポートしています。それは確かにベンチマークの価値がある。

+0

+1これは実際にはOracleでより効率的です。 –

4

私の小規模なデータセットでは、ほとんどの場合、Oracleは表に触れずに主キー索引を使用する全く同じ計画を出します。例外はプランのコストが高いにもかかわらず一貫性のある取得回数を減らすMINUSバージョンです。

--Create Sample Data. 
d r o p table tableA; 
d r o p table tableB; 

create table tableA as (
    select rownum-1 ID, chr(rownum-1+70) bb, chr(rownum-1+100) cc 
     from dual connect by rownum<=4 
); 

create table tableB as (
    select rownum ID, chr(rownum+70) data1, chr(rownum+100) cc from dual 
    UNION ALL 
    select rownum+2 ID, chr(rownum+70) data1, chr(rownum+100) cc 
     from dual connect by rownum<=3 
); 

a l t e r table tableA Add Primary Key (ID); 
a l t e r table tableB Add Primary Key (ID); 

--View Tables. 
select * from tableA; 
select * from tableB; 

--Find all rows in tableA that don't have a corresponding row in tableB. 

--Method 1. 
SELECT id FROM tableA WHERE id NOT IN (SELECT id FROM tableB) ORDER BY id DESC; 

--Method 2. 
SELECT tableA.id FROM tableA LEFT JOIN tableB ON (tableA.id = tableB.id) 
WHERE tableB.id IS NULL ORDER BY tableA.id DESC; 

--Method 3. 
SELECT id FROM tableA a WHERE NOT EXISTS (SELECT 1 FROM tableB b WHERE b.id = a.id) 
    ORDER BY id DESC; 

--Method 4. 
SELECT id FROM tableA 
MINUS 
SELECT id FROM tableB ORDER BY id DESC; 
+1

'd r o p'を書くために、人々にコードを読ませ、+1を得る – Flavius

関連する問題