【问题标题】:How to improve NOT EXISTS performance in Oracle如何在 Oracle 中提高 NOT EXISTS 性能
【发布时间】:2014-04-25 07:32:14
【问题描述】:
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 语句如下所示。 table1 和 table3 有超过 1000000 行,table2 有 100 行。这个 SQL 语句很慢。完成需要100多秒。有什么办法可以改善吗?

【问题讨论】:

  • 最好使用 MERGE 语句。
  • 你能说明你在这三个表上都有哪些索引和约束吗?
  • 另外,tbl1tbl2 之间的交叉连接是故意的吗?我觉得缺少连接谓词...
  • 感谢您的回复。我需要将数据插入table3。这些数据是通过连接 table1 和 table2 选择的。 table3中已经存在一些join结果,所以我需要使用NOT EXISTS来移除这些结果。
  • 我认为table3tbl3 是一个错字。为了清楚起见,可能应该更正一下。

标签: sql oracle not-exists sql-tuning


【解决方案1】:

我发现很难提高这条 SQL 语句的性能。我测试了 MERGE,但是它需要超过 200 秒。即使性能可以提高,我估计也只能提高1秒或2秒,这不符合我们的业务需求。 (我有大约 20 条这样的 SQL 语句)。 于是我回顾了我们的业务逻辑,发现这个SQL语句是没有必要的。我们只需要一个更仔细的算法来收集新数据,制作一个笛卡尔积,然后将这些新数据插入到 table3 中。这样,这条SQL语句就可以去掉了。而新的过程只需要几秒钟! 我想当我们改进一条SQL语句时,请首先确定这条SQL语句是绝对必要的。

【讨论】:

    【解决方案2】:

    使用 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);
    

    【讨论】:

    • 我测试了 MERGE。在我的服务器上,它实际上慢了两倍。
    • table3有索引吗?如果没有,请在 (pk_1, pk_2, pk_3, pk_4) 上创建复合索引后尝试。
    • 是的,pk_1,pk_2,pk_3,pk_4是综合索引
    【解决方案3】:

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

    FROM
      table1 tbl1, table2 tbl2
    

    您(可能不小心)在 table1 和 table2 之间生成笛卡尔积,内存中有 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
    

    【讨论】:

    • table1 和 table2 是独立的。我们的应用程序需要在 table1 和 table2 之间做一个笛卡尔积。我认为瓶颈是“不存在”,它需要“嵌套循环反”搜索。我想知道有什么可以更好地“不存在”。
    • 好的,我明白了。那么您希望每次更新有多少记录? IE。 NOT EXISTS 谓词会再次删除从笛卡尔积产生的大部分元组吗?
    • 是的。虽然笛卡尔积数百万行,但只有几行(大约 100 行)会通过“NOT EXISTS”条件。
    • 那么我同意MERGE 可能会胜过INSERT .. SELECT
    • 非常感谢。在我的服务器上,MERGE 的运行速度比 INSERT .. SELECT 慢。我找到了绕过“不存在”部分的方法。它与我们的业务逻辑有关,因此开发人员以前从未想过这个方向。现在我可以删除这条 SQL 语句了。再次感谢您的回复。
    猜你喜欢
    • 2010-10-07
    • 1970-01-01
    • 2021-08-31
    • 2022-06-15
    • 1970-01-01
    • 2011-10-14
    • 2013-01-16
    • 2011-01-24
    • 2014-09-01
    相关资源
    最近更新 更多