我在两张桌子之间有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的全表扫描。我想避免全表扫描。
如何重写此查询以快速运行?我应该用什么指数?
答案 0 :(得分:86)
select tableA.id from tableA left outer join tableB on (tableA.id = tableB.id)
where tableB.id is null
order by tableA.id desc
如果你的数据库知道如何进行索引交叉,那么这只会触及主键索引
答案 1 :(得分:30)
您也可以使用exists
,因为有时它比left join
更快。你必须对它们进行基准测试,以确定你想要使用哪一个。
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:
答案 2 :(得分:6)
您必须针对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
这可能会更快;它当然值得基准测试。
答案 3 :(得分:5)
对于我的小数据集,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;
答案 4 :(得分:3)
我无法告诉你哪些方法在H2上最好(或者即使它们都能正常工作),但我写了一篇文章,详细介绍了TSQL中可用的所有(好)方法。你可以给他们一个镜头,看看他们中的任何一个是否适合你:
答案 5 :(得分:0)
select parentTable.id from parentTable
left outer join childTable on (parentTable.id = childTable.parentTableID)
where childTable.id is null