Oracle:快速NOT IN用于多列

时间:2010-12-03 12:35:41

标签: sql oracle

我需要同步两个表。我们假设这些表包含以下列:

Table1: A, B, C, D  
Table2: A, B, C, E

我需要在Table1中找到这样的行,表2中没有对应(A, B, C)值的条目,然后将E计算为F(D)并更新Table2。

如果我需要匹配,例如只有A,我会写下面的查询:

SELECT * FROM Table1 WHERE A NOT IN (SELECT A FROM Table2)

多列模拟似乎太慢了:

SELECT * FROM Table1 WHERE A NOT IN (SELECT A FROM Table2)
                       AND B NOT IN (SELECT B FROM Table2)
                       AND C NOT IN (SELECT C FROM Table2)

编写此类查询的最佳方法是什么?

6 个答案:

答案 0 :(得分:20)

如果两个表中的(a,b,c)都是非空的,那么NOT IN和NOT EXISTS很可能(在我试过的验证中)生成相同的执行计划。

如果(a,b,c)被声明为可空,但是你知道这些列实际上不是空的,你可以通过添加“欺骗优化器来进行散列反连接”和a不为空,并且b不为空,并且对于您的查询,c不为空。 (您可能还需要在子查询中添加/ * + HASH_AJ * /提示。)

此外,以下查询不相同:

 from table1
where (a,b,c) not in (select a,b,c from table2)

 from table1
where a not in(select a from table2)
  and b not in(select b from table2)
  and c not in(select c from table2)

答案 1 :(得分:6)

   SELECT * FROM Table1 
   WHERE (A, B, C) NOT IN 
     (SELECT A,B,C FROM Table2)

答案 2 :(得分:0)

SELECT * FROM Table1 
WHERE 
not exist (
  SELECT 1 FROM Table2 
  where Table2.a=Table1.a 
  and Table2.b=Table1.b 
  and Table2.c=Table1.c )

编辑:注意不存在和NOT IN在某些情况下不完全相同(NULL值) 见:http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::p11_question_id:442029737684

答案 3 :(得分:0)

你可以尝试

SELECT * FROM Table1 
WHERE 
not exists (
  SELECT 1 FROM Table2 
  where Table2.a=Table1.a 
  and Table2.b=Table1.b 
  and Table2.c=Table1.c );

由guigui42发布。它执行散列连接反并避免过滤。

或尝试

select t1.*
from table1 t1, table2 t2
where t1.a = t2.a(+)
and t1.b = t2.b(+)
and t1.c = t2.c(+)
and (t2.a is null or t2.b is null or t2.c is null);

这是一个外连接+过滤器。其他两个应该比做一个NOT IN快得多。

答案 4 :(得分:0)

一个小附录:我发现当NOT IN子句包含多个列时,Oracle(我的情况下为11gR1)拒绝散列反连接,例如,

SELECT * FROM Table1 WHERE (A,B,C) NOT IN (
    SELECT /*+ HASH_AJ */ A,B,C FROM Table2
        WHERE A IS NOT NULL AND B IS NOT NULL AND C IS NOT NULL
)

这甚至在添加其中一个提示(与UNNEST相同)和非NULL条件时也是如此。只有一列它可以工作。

答案 5 :(得分:0)

出于性能原因,从不这样做

NOT IN (SELECT

使用

NOT EXISTS   (SELECT 1 FROM