由函数引起的Oracle 11中的变异表

Dan*_* A. 13 sql oracle plsql oracle10g oracle11g

我们最近从Oracle 10升级到Oracle 11.2.升级后,我开始看到由函数而不是触发器引起的变异表错误(我之前从未遇到过).它是在旧版Oracle中运行的旧代码.

这是一个会导致错误的场景:

create table mutate (
    x NUMBER,
    y NUMBER
);

insert into mutate (x, y)
values (1,2);

insert into mutate (x, y)
values (3,4);
Run Code Online (Sandbox Code Playgroud)

我创建了两行.现在,我将通过调用此语句来加倍我的行:

insert into mutate (x, y)
select x + 1, y + 1 
from mutate;
Run Code Online (Sandbox Code Playgroud)

这对于复制错误并不是绝对必要的,但它有助于我以后的演示.所以表格的内容现在看起来像这样:

X,Y
1,2
3,4
2,3
4,5
Run Code Online (Sandbox Code Playgroud)

一切都很好.现在是有趣的部分:

create or replace function mutate_count
return PLS_INTEGER
is
    v_dummy PLS_INTEGER;
begin
    select count(*) 
    into v_dummy
    from mutate;

    return v_dummy;
end mutate_count;
/
Run Code Online (Sandbox Code Playgroud)

我创建了一个函数来查询我的表并返回一个计数.现在,我将它与INSERT语句结合起来:

insert into mutate (x, y)
select x + 2, y + 2
from mutate
where mutate_count() = 4;
Run Code Online (Sandbox Code Playgroud)

结果?这个错误:

ORA-04091: table MUTATE is mutating, trigger/function may not see it
ORA-06512: at "MUTATE_COUNT", line 6
Run Code Online (Sandbox Code Playgroud)

所以我知道导致错误的原因,但我很好奇为什么.Oracle是否执行SELECT,检索结果集,然后执行这些结果的批量插入?如果在查询完成之前已经插入了记录,我只会期望发生变异表错误.但是,如果甲骨文这样做,那么早先的声明是不是:

insert into mutate (x, y)
select x + 1, y + 1 
from mutate;
Run Code Online (Sandbox Code Playgroud)

开始无限循环?

更新:

通过Jeffrey的链接,我在Oracle文档中找到了这个:

默认情况下,Oracle保证语句级读取一致性.单个查询返回的数据集与单个时间点一致.

作者在帖子中也有评论:

有人可能会争论为什么Oracle不能确保出现在SQL语句中的重复函数调用的"语句级读取一致性".就我而言,它可能被视为一个错误.但这是它目前的工作方式.

假设Oracle版本10和11之间的这种行为发生了变化,我是否正确?

Jef*_*emp 9

首先,

insert into mutate (x, y)
select x + 1, y + 1 
from mutate;
Run Code Online (Sandbox Code Playgroud)

不启动无限循环,因为查询不会看到插入的数据 - 只显示从语句开头起存在的数据.新行仅对后续语句可见.

很好地解释了:

当Oracle退出当前正在执行update语句的SQL引擎并调用该函数时,此函数 - 就像后续行更新触发器一样 - 将在执行更新期间看到EMP的中间状态声明.这意味着函数调用的返回值在很大程度上取决于行更新的顺序.


zep*_*zep 8

语句级读取一致性和事务级读取一致性".

从手册:

"如果一个SELECT列表包含一个函数,那么数据库在应用语句级读一致性的PL/SQL函数代码中的SQL运行语句级别,而不是在父SQL水平.例如,函数可以访问表其数据由另一个用户更改和提交.对于函数中每次执行SELECT,都会建立一个新的读取一致性快照".

这两个概念都在"Oracle®数据库概念"中进行了解释:

http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/consist.htm#sthref1955


- >>> 更新

- >>>*OP关闭后添加的部分

规则

技术规则由Kemp先生(@ jeffrey-kemp)和Toon Koppelaars 在这里很好地解释,在"Pl/Sql语言参考 - 控制PL/SQL子程序的副作用 "中报告(你的函数违反RNDS读取没有数据库)州):

从INSERT,UPDATE或DELETE语句调用时,该函数无法查询或修改由该语句修改的任何数据库表.

如果函数查询或修改表,并且该表上的DML语句调用该函数,则会发生ORA-04091(变异表错误).

SQL语句可以调用的PL/SQL函数