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之间的这种行为发生了变化,我是否正确?
首先,
insert into mutate (x, y)
select x + 1, y + 1
from mutate;
Run Code Online (Sandbox Code Playgroud)
不启动无限循环,因为查询不会看到插入的数据 - 只显示从语句开头起存在的数据.新行仅对后续语句可见.
这很好地解释了:
当Oracle退出当前正在执行update语句的SQL引擎并调用该函数时,此函数 - 就像后续行更新触发器一样 - 将在执行更新期间看到EMP的中间状态声明.这意味着函数调用的返回值在很大程度上取决于行更新的顺序.
语句级读取一致性和事务级读取一致性".
从手册:
"如果一个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(变异表错误).
| 归档时间: |
|
| 查看次数: |
4105 次 |
| 最近记录: |