匿名PL/SQL块与本机SQL的性能比较

匿名PL/SQL块与本机SQL的性能比较,sql,oracle,performance,plsql,locking,Sql,Oracle,Performance,Plsql,Locking,我有一个SQL语句,当在PL/SQL块中执行时,它会提供显著不同的性能 SQL非常简单 INSERT into Existing_Table SELECT col1,col2... from Other_table where rownum < 100000 插入现有_表选择col1、col2。。。来自rownum

我有一个SQL语句,当在PL/SQL块中执行时,它会提供显著不同的性能

SQL非常简单

INSERT into Existing_Table SELECT col1,col2... from Other_table where rownum < 100000
插入现有_表选择col1、col2。。。来自rownum<100000的其他_表
当它作为SQL执行时,它几乎立即返回

但在匿名PL/SQL块内执行时,它将永远挂起:

begin
    INSERT into Existing_Table SELECT col1, col2... from Other_table where rownum < 100000;
end;
/
开始
插入到现有表格中,选择col1、col2。。。来自rownum<100000的其他_表;
结束;
/
但在匿名PL/SQL块内执行时,它将永远挂起:

begin
    INSERT into Existing_Table SELECT col1, col2... from Other_table where rownum < 100000;
end;
/
我猜有两件事:

  • 您的表(现有_表)在insert语句中使用的一列上有一个约束
  • 您忘记在执行SQL语句和PL/SQL匿名块之间发出commit
  • 在SQL和PL/SQL中执行语句不应该有性能上的差异。它应该在几乎相同的时间内执行。 但是由于约束或提交,它被阻止,因为行被锁定

    这里有一个例子

    在会话1中,创建两个表。一个有约束,一个没有:

    create table Existing_Table 
    (
      existing_column number primary key
    );
    
    create table Existing_Table_2
    (
      existing_column number
    );    
    
    在同一会话上,执行以下SQL语句:

    insert into Existing_Table (existing_column) values (1);
    
    结果:

    1 row inserted.
    
    在另一个(会话2)上,执行以下PL/SQL匿名块:

    begin
      insert into Existing_Table (existing_column) values (1);
    end;
    
    这将一直挂起,直到您在会话1中发出提交

    这是因为会话1为现有的_列“保留”了值“1”,并且在您发出提交时将“保存”。 会话2只是等待会话1提交或回滚插入

    现在,当我返回会话1并发出提交时,该行将被解锁。 但是,由于完整性约束冲突,会话2将导致错误:

    Error starting at line : 1 in command -
    begin
      insert into Existing_Table (existing_column) values (1);
    end;
    Error report -
    ORA-00001: unique constraint (APPS.SYS_C001730810) violated
    ORA-06512: at line 2
    00001. 00000 -  "unique constraint (%s.%s) violated"
    *Cause:    An UPDATE or INSERT statement attempted to insert a duplicate key.
               For Trusted Oracle configured in DBMS MAC mode, you may see
               this message if a duplicate entry exists at a different level.
    *Action:   Either remove the unique restriction or do not insert the key.
    
    现在,另一个没有约束的表示例

    在会话3中运行以下SQL,但不进行提交:

    insert into Existing_Table_2 (existing_column) values (1);
    
    结果:

    1 row inserted.
    
    PL/SQL procedure successfully completed.
    
    在会话4中的匿名PL/SQL块中运行相同的SQL:

    begin
      insert into Existing_Table_2 (existing_column) values (1);
    end;
    
    结果:

    1 row inserted.
    
    PL/SQL procedure successfully completed.
    
    即使在会话1中没有提交,它也可以插入,因为没有违反任何约束

    请注意,在发出提交之前,会话3和会话4中的任何数据都不会实际保存在数据库中

    在此处查看有关会话阻塞的其他文章:


    我试图重新创建问题,但未能成功。正如其他人正确指出的那样,SQL非常简单,作为SQL或非PL/SQL执行它不应该有什么不同


    我唯一想到的是,我可能没有注意到是否有另一个会话在没有提交/回滚的情况下尝试DML;这可能导致了绞刑。因此,BobC和Migs Isip提到的情景可能与此相关。谢谢大家。

    我想到的一个原因是匿名。如果将其放在过程中并多次调用,性能可能会发生变化。但对于纯sql操作,真正的测试方法是刷新所有内存缓存。您可能有很好的性能,因为其他用户(或您自己)一直在访问这些表,这可能会产生误导。发布这些表可能会更好,因为这样简单,应该没有区别。我所能想到的唯一一件事是,在现有的_表上有一个唯一的索引;运行第一个SQL而不提交,然后从另一个会话运行PL/SQL。第二个会话正在等待提交,然后才能确定索引中是否有重复项…我将执行一些标准故障排除来比较这两个版本。等待的慢的是什么?执行计划是否相同?如果提到的答案/评论对您有所帮助,请单击复选标记接受答案,以便其他人也可以接受指导。