Sql 如何提高Oracle中不存在的性能

Sql 如何提高Oracle中不存在的性能,sql,oracle,not-exists,sql-tuning,Sql,Oracle,Not Exists,Sql Tuning,我的SQL语句如下所示。表1和表3有超过1000000行,表2有100行。这个SQL语句非常慢。完成这项工作需要100多秒。有什么办法可以改进吗?我很确定您的表表达式不完整: 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 F

我的SQL语句如下所示。表1和表3有超过1000000行,表2有100行。这个SQL语句非常慢。完成这项工作需要100多秒。有什么办法可以改进吗?

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

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) 
;
您(可能是意外地)在表1和表2之间生成了一个笛卡尔积,内存中有1000000 x 100条记录。您的表表达式可能应为:

FROM
  table1 tbl1, table2 tbl2
或者更好(防止将来发生这种事情)


使用合并,服务速度更快

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

我发现很难提高这个SQL语句的性能。我测试合并,但是它需要200多秒。即使性能可以提高,我想也只能提高1到2秒,这不符合我们的业务需求。(我有大约20条像这样的SQL语句)。 所以我回顾了我们的业务逻辑,发现这个SQL语句不是必需的。我们只需要一个更仔细的算法来收集新数据,生成笛卡尔积,然后将新数据插入表3。这样,这个SQL语句就可以被删除。而新的过程只需要几秒钟!
我认为,当我们改进SQL语句时,请首先确保该SQL语句是绝对必要的。

最好使用MERGE语句。您能说明在所有三个表上都有哪些索引和约束吗?另外,您的
tbl1
tbl2
之间的交叉连接是故意的吗?我觉得缺少一个连接谓词…谢谢你的回复。我需要在表3中插入数据。这些数据由联接表1和表2选择。表3中已经存在一些联接结果,因此我需要使用NOT exists删除这些结果。我假设
table3
tbl3
是一个输入错误。为了清楚起见,可能需要更正。表1和表2是独立的。我们的应用程序需要在表1和表2之间进行笛卡尔积。我认为瓶颈是“不存在”,这需要“嵌套循环”搜索。我想知道还有什么比“不存在”更好的方法。好吧,我明白了。那么,您希望每次更新有多少条记录?也就是说,
不存在
谓词是否会再次删除笛卡尔乘积产生的大部分元组?是的。虽然笛卡尔乘积有数百万行,但只有少数行(大约100行)会通过“不存在”条件。那么我同意
MERGE
可能会优于此
INSERT。。选择
。非常感谢。在我的服务器上,“合并”比“插入”慢。。选择。我找到了绕过“不存在”部分的方法。它与我们的业务逻辑相关,因此开发人员以前从未考虑过这个方向。现在我可以删除这个SQL语句了。再次感谢您的回复。我测试了合并。在我的服务器上,它实际上慢了两倍。表3上有索引吗?如果没有,请在(pk_1、pk_2、pk_3、pk_4)上创建复合索引后重试。是的,pk_1、pk_2、pk_3、pk_4是复合索引
FROM
  table1 tbl1
JOIN
  table2 tbl2 ON tbl1.some_column = tbl2.some_column
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);