75

我在两个表之间有 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(Java 嵌入式数据库),这会导致 tableB 的全表扫描。我想避免全表扫描。

如何重写此查询以快速运行?我应该使用什么索引?

4

6 回答 6

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

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

于 2009-09-12T16:09:32.683 回答
33

您也可以使用exists,因为有时它比left join. 您必须对它们进行基准测试以确定您要使用哪一个。

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

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

left join- 总子树成本:1.09724:

左连接

exists- 总子树成本:1.07421:

存在

于 2009-09-12T16:15:47.180 回答
7

您必须对照表 B 中的每个 ID 检查表 A 中的每个 ID。功能齐全的 RDBMS(例如 Oracle)将能够将其优化为 INDEX FULL FAST SCAN 而根本不接触表。我不知道 H2 的优化器是否这么聪明。

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

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

这可能会执行得更快;这当然值得进行基准测试。

于 2009-09-12T16:18:49.890 回答
6

对于我的小数据集,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;
于 2010-12-10T14:36:54.853 回答
3

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

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

于 2009-09-12T16:17:13.340 回答
-1
select parentTable.id from parentTable
left outer join childTable on (parentTable.id = childTable.parentTableID) 
where childTable.id is null
于 2018-07-21T11:59:00.437 回答