如何提高Oracle中NOT EXISTS的性能


INSERT INTO table3
SELECT
  tbl1.pk_1, tbl1.pk_2, tbl2.pk_3, tbl1.pk4
FROM
  table1 tbl1, table2 tbl2
WHERE
  tbl1.pk_1 = 'root' and
  NOT EXISTS 
    (SELECT 1 FROM table3 tbl3
     WHERE tbl3.pk_1 = tbl1.pk_1 and tbl3.pk_2 = tbl1.pk_2 and tbl3.pk_3 = tbl2.pk_3 and tbl3.pk_4 = tbl1.pk_4) 
;

我的SQL语句看起来像这样。表1和表3有超过1000000行,表2有100行。这个SQL语句非常慢。全程耗时超过100秒。有什么办法可以改进吗?

使用MERGE,速度更快

merge into table3 tbl3
using (select tbl1.pk_1, tbl1.pk_2, tbl2.pk_3, tbl1.pk4
         from table1 tbl1, table2 tbl2
        where tbl1.pk_1 = 'root') tb1
   on (tbl3.pk_1 = tbl.pk_1 and tbl3.pk_2 = tbl.pk_2 and tbl3.pk_3 = tbl.pk_3 and tbl.pk_4 = tbl1.pk_4) 
when not matched then 
     insert (tbl3.pk_1, tbl3.pk_2, tbl3.pk_3, tbl3.pk_4)
     VALUES (tbl.pk_1, tbl.pk_2, tbl.pk_3, tbl.pk_4);

我发现提高这个SQL语句的性能是非常困难的。我测试了MERGE,但是它需要200多秒。即使性能可以提高,我想也只能提高1到2秒,这并不能满足我们的业务需求。(我有大约20个这样的SQL语句)。所以我检查了我们的业务逻辑,发现这个SQL语句是不必要的。我们只需要一个更仔细的算法来收集新数据,做一个笛卡尔积,然后将这个新数据插入到表3中。通过这种方式,可以删除此SQL语句。新的过程只需要几秒钟!我认为当我们改进一个SQL语句时,请首先确保这个SQL语句是绝对必要的。

我很确定你的表表达式是不完整的:

FROM
  table1 tbl1, table2 tbl2

您(可能不小心)在表1和表2之间生成了一个笛卡尔积,内存中有1000000 x 100条记录。您的表表达式可能应该是:

FROM
  table1 tbl1, table2 tbl2
WHERE
  tbl1.some_column = tbl2.some_column

或者更好(为了防止将来发生这样的事情)

FROM
  table1 tbl1
JOIN
  table2 tbl2 ON tbl1.some_column = tbl2.some_column

最新更新