【问题标题】:Performance of Anonymous PL/SQL Block versus Native SQL匿名 PL/SQL 块与本机 SQL 的性能
【发布时间】:2017-06-09 15:03:58
【问题描述】:

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

SQL 非常简单。

INSERT into Existing_Table SELECT col1,col2... from Other_table where rownum < 100000

当它作为 SQL 执行时,它几乎立即返回。

但是当在匿名 PL/SQL 块中执行时,它会永远挂起:

begin
    INSERT into Existing_Table SELECT col1, col2... from Other_table where rownum < 100000;
end;
/

【问题讨论】:

  • 我想到的一个原因是匿名。如果你把它放在一个过程中并调用它几次,性能可能会改变。但是对于您的纯sql操作,真正的测试方法是刷新所有内存缓存。您可能有很好的表现,因为其他用户(或您自己)一直在访问这些表,这可能会产生误导。
  • dba.stackexchange.com上发布这个可能会更好
  • 对于这么简单的事情,应该没有区别。我能想到的唯一能做到这一点的事情(这与 PL/SQL 无关)是你在 EXISTING_TABLE 上有一个唯一索引;您在不提交的情况下运行第一个 SQL,然后从另一个会话运行 PL/SQL。第二个会话等待提交,然后才能确定您的索引中是否有重复...
  • 我会做一些标准的故障排除来比较两个版本。慢的在等什么,执行计划一样吗?

标签: sql oracle performance plsql locking


【解决方案1】:

但是当在匿名 PL/SQL 块中执行时,它会永远挂起:

我猜两件事:

  1. 您的表 (Existing_Table) 对您在插入语句中使用的列之一具有约束。
  2. 您忘记在执行 SQL 语句和 PL/SQL 匿名块之间发出提交。

在 SQL 和 PL/SQL 中执行您的语句在性能上应该没有差异。它应该在几乎相同的时间内执行。 但是由于 Constraint 或 Commit,它被阻塞了,因为行被锁定了。

这是一个例子。

在会话 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;

这将一直挂起,直到您在 Session 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.

在会话 4 的匿名 PL/SQL 块内运行相同的 SQL:

begin
  insert into Existing_Table_2 (existing_column) values (1);
end;

结果:

PL/SQL procedure successfully completed.

即使在会话 1 中没有提交,它也可以正常插入,因为没有违反任何约束。

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

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

Tracking Oracle blocking sessions

Find blocking sessions

【讨论】:

    【解决方案2】:

    我试图重现问题,但无法重现。正如其他人正确指出的那样,SQL 足够简单,并且将其作为 SQL 或非 PL/SQL 执行应该不会有什么不同。

    我唯一想到的是,我可能没有注意到我是否有另一个会话尝试没有 COMMIT/ROLLBACK 的 DML;这可能导致挂起。所以 BobC 和 Migs Isip 提到的场景可能与这里有关。谢谢大家。

    【讨论】:

    • 如果提到的答案/评论对您有所帮助,请点击复选标记接受答案,以便其他人也可以得到指导。
    猜你喜欢
    • 2014-09-30
    • 2017-09-02
    • 1970-01-01
    • 2017-01-29
    • 1970-01-01
    • 2015-01-08
    • 1970-01-01
    • 1970-01-01
    • 2013-05-22
    相关资源
    最近更新 更多