如何在一个表中查找在另一个表中没有对应行的行

Ste*_*eod 66 sql optimization h2

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

SELECT id 
  FROM tableA 
 WHERE id NOT IN (SELECT id 
                    FROM tableB) 
ORDER BY id desc
Run Code Online (Sandbox Code Playgroud)

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

使用H2(Java嵌入式数据库),这会导致tableB的全表扫描.我想避免全表扫描.

如何重写此查询以快速运行?我应该用什么指数?

Squ*_*Cog 89

select tableA.id from tableA left outer join tableB on (tableA.id = tableB.id)
where tableB.id is null
order by tableA.id desc 
Run Code Online (Sandbox Code Playgroud)

如果您的数据库知道如何进行索引交叉,那么这只会触及主键索引

  • 这就是我喜欢Stack Overflow的原因.星期六,SQL问题 - 问题在5分钟内准确回答! (9认同)
  • 你在其他答案中也得到了一些好的建议.当然我认为我的速度最快:-)但数据库实现差异很大,我没有H2的经验.如果您对不同方法进行基准测试并使用结果更新问题,那将会很棒. (2认同)

Eri*_*ric 32

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

select
    id
from
    tableA a
where
    not exists
    (select 1 from tableB b where b.id = a.id)
Run Code Online (Sandbox Code Playgroud)

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

left join - 总子树成本:1.09724:

离开加入

exists - 总子树成本:1.07421:

存在

  • `存在`不使用标准的相关子查询.它使用半连接.SQL Server 2008上用于"左连接"的执行计划是两个索引扫描到一个哈希匹配到过滤器到一个选择.对于`not exists`,它是对一个选择的哈希匹配的两个索引扫描 - 没有过滤器.`exists`哈希匹配实际上比`left join'略快.`left join`的总成本为1.09,``DimCustomer`为`AdventureWorksDW`为`AdventureWorksDW2008`的'不存在'为1.07. (2认同)

APC*_*APC 7

您必须检查tableA中的每个ID与tableB中的每个ID.功能齐全的RDBMS(例如Oracle)可以将其优化为INDEX FULL FAST SCAN而不是触及表格.我不知道H2的优化器是否像那样聪明.

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

select id from tableA
minus
select id from tableB
order by id desc
Run Code Online (Sandbox Code Playgroud)

这可能会更快; 它当然值得基准测试.


Lei*_*fel 5

对于我的小型数据集,Oracle几乎为所有这些查询提供了使用主键索引的完全相同的计划,而无需涉及表。MINUS版本是个例外,尽管计划成本较高,但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;
Run Code Online (Sandbox Code Playgroud)