如何在一个表中find在另一个表中没有相应行的行

我有两个表之间的1:1关系。 我想查找表A中没有表B中相应行的所有行。我使用这个查询:

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

id是两个表中的主键。 除了主键索引之外,我还有一个tableA(id desc)索引。

使用H2(Javaembedded式数据库),这将导致tableB的全表扫描。 我想避免全表扫描。

我怎样才能重写这个查询来快速运行? 我应该怎样指数?

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

如果你的数据库知道如何做索引交点,这只会触及主键索引

你也可以使用exists ,因为有时比left join快。 你必须对他们进行基准testing,找出你想使用哪一个。

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

为了说明exists可以比left join更有效,下面是SQL Server 2008中这些查询的执行计划:

left join – 总子树成本:1.09724:

左加入

exists – 总的子树成本:1.07421:

存在

你必须检查tableA中每个ID的每个ID。 一个全function的RDBMS(如Oracle)将能够优化到一个索引完全快速扫描,而不是触摸表。 我不知道H2的优化器是否如此聪明。

H2确实支持MINUS语法,所以你应该试试这个

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

这可能会执行得更快; 这当然值得标杆。

对于我的小数据集,Oracle给几乎所有这些查询提供完全相同的使用主键索引的计划,而不用接触表。 尽pipe计划成本较高,但是MINUS版本除了可以获得较less的一致性外,

 --Create Sample Data. drop table tableA; drop 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 ); alter table tableA Add Primary Key (ID); alter 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; 

我不能告诉你哪些方法在H2上是最好的(或者即使它们都能工作),但我写了一篇文章,详细介绍了TSQL中可用的所有方法。 你可以给他们一个镜头,看看他们中的任何一个是否适合你:

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