由功能引起的Oracle 11中的表突变 [英] Mutating Table in Oracle 11 caused by a function

查看:65
本文介绍了由功能引起的Oracle 11中的表突变的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们最近已从Oracle 10升级到Oracle 11.2.升级后,我开始看到由函数而不是触发器引起的变异表错误(我从未遇到过).这是旧的代码,可以在Oracle的早期版本中使用.

We've recently upgraded from Oracle 10 to Oracle 11.2. After upgrading, I started seeing a mutating table error caused by a function rather than a trigger (which I've never come across before). It's old code that worked in prior versions of Oracle.

以下是会导致错误的情况:

Here's a scenario that will cause the error:

create table mutate (
    x NUMBER,
    y NUMBER
);

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

insert into mutate (x, y)
values (3,4);

我已经创建了两行.现在,我将通过调用以下语句将行加倍:

I've created two rows. Now, I'll double my rows by calling this statement:

insert into mutate (x, y)
select x + 1, y + 1 
from mutate;

这并不是重复错误的严格条件,但以后的演示会有所帮助.因此,表的内容现在看起来像这样:

This isn't strictly necessary to duplicate the error, but it helps with my demonstration later. So the contents of the table now look like this:

X,Y
1,2
3,4
2,3
4,5

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

All is well. Now for the fun part:

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;
/

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

I've created a function to query my table and return a count. Now, I'll combine that with an INSERT statement:

insert into mutate (x, y)
select x + 2, y + 2
from mutate
where mutate_count() = 4;

结果?错误:

ORA-04091: table MUTATE is mutating, trigger/function may not see it
ORA-06512: at "MUTATE_COUNT", line 6

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

So I know what causes the error, but I am curious as to the why. Isn't Oracle performing the SELECT, retrieving the result set, and then performing a bulk insert of those results? I would only expect a mutating table error if records were already being inserted before the query finished. But if Oracle did that, wouldn't the earlier statement:

insert into mutate (x, y)
select x + 1, y + 1 
from mutate;

开始无限循环吗?

更新:

通过Jeffrey的链接,我在 Oracle docs中找到了此链接:

Through Jeffrey's link I found this in the Oracle docs:

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

By default, Oracle guarantees statement-level read consistency. The set of data returned by a single query is consistent with respect to a single point in time.

他的帖子中也有来自作者的评论:

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

One could argue why Oracle doesn't ensure this 'statement-level read consistency' for repeated function calls that appear inside a SQL statement. It could be considered a bug as far as I'm concerned. But this is the way it currently works.

我是否假设Oracle 10和11版本之间的行为已发生更改是正确的?

Am I correct in assuming that this behavior has changed between Oracle versions 10 and 11?

推荐答案

首先,

insert into mutate (x, y)
select x + 1, y + 1 
from mutate;

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

Does not start an infinite loop, because the query will not see the data that was inserted - only data that existed as of the start of the statement. The new rows will only be visible to subsequent statements.

说明很好:

当Oracle退出当前正在执行的SQL引擎时, 更新语句,并调用该函数,然后调用此函数-只是 就像行后更新触发器一样-看到中间状态 在执行更新语句期间存在的EMP.这 意味着我们函数调用的返回值很大 取决于行发生更新的顺序.

When Oracle steps out of the SQL-engine that's currently executing the update statement, and invokes the function, then this function -- just like an after row update trigger would -- sees the intermediate states of EMP as they exist during execution of the update statement. This implies that the return value of our function invocations heavily depend on the order in which the rows happen to be updated.

这篇关于由功能引起的Oracle 11中的表突变的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆