web-dev-qa-db-ja.com

別のテーブルに対応する行がない1つのテーブルの行を見つける方法

2つのテーブル間に1対1の関係があります。テーブルBに対応する行がないテーブルAのすべての行を検索します。このクエリを使用します。

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

idは両方のテーブルの主キーです。主キーインデックスとは別に、tableA(id desc)にもインデックスがあります。

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

このクエリを書き換えてすばやく実行するにはどうすればよいですか?どのインデックスを使用する必要がありますか?

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

データベースがインデックスの交差を行う方法を知っている場合、これは主キーインデックスのみに影響します

89
SquareCog

left joinよりも高速な場合があるため、existsも使用できます。どのベンチマークを使用するかを判断するには、ベンチマークを行う必要があります。

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

existsleft joinよりも効率的であることを示すために、SQL Server 2008でのこれらのクエリの実行計画を以下に示します。

left join-サブツリーの合計コスト:1.09724:

left join

exists-サブツリーの総コスト:1.07421:

exists

31
Eric

TableBのすべてのIDに対してtableAのすべてのIDを確認する必要があります。完全な機能を備えたRDBMS(Oracleなど)は、それをINDEX FULL FAST SCANに最適化でき、テーブルにはまったく触れません。 H2のオプティマイザーがそれほどスマートかどうかはわかりません。

H2はMINUS構文をサポートしているため、これを試してください

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

より高速に実行される可能性があります。確かにベンチマークする価値があります。

7
APC

私の小さなデータセットの場合、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;
5
Leigh Riffel

これらのメソッドのどれがH2に最適であるか(またはすべてが機能する場合でも)を言うことはできませんが、TSQLで使用可能なすべての(良い)メソッドを詳述する記事を書きました。あなたは彼らに一撃を与え、それらのどれかがあなたのために働くかどうか見ることができます:

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

3
Aaron Alton
select parentTable.id from parentTable
left outer join childTable on (parentTable.id = childTable.parentTableID) 
where childTable.id is null
0
Faysal Maqsood