在此上下文中的“语句”是一个DML语句:单个
SELECT
,
INSERT
,
UPDATE
,
DELETE
,
MERGE
.
它是
不
PL/SQL块。同样,同一DML语句的多个执行(例如,在pl/sql循环中)是单独的“语句”。如果您需要多个语句或一个pl/sql块内的一致性,可以使用
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
或
SET TRANSACTION READ ONLY
. 两者都会带来局限性。
不一致读取的相反示例如下。
启动条件:表
BIG_TABLE
有1000万行。
10:00用户A:
SELECT COUNT(*) FROM BIG_TABLE;
10:01用户B:
DELETE FROM BIG_TABLE WHERE ID >= 9000000; -- delete the last million rows
10:02用户B:
COMMIT;
10:03用户A:查询完成:
COUNT(*)
--------------
9309129
那是错误的。用户A应该得到1000万行或者900万行。根本没有9309129
坚信的
表中的行。发生的情况是,在Oracle实际处理删除之前(或在
COMMIT
)然后,在用户b删除/提交之后,用户a的查询停止看到删除的行,并停止对它们计数。
这类问题在Oracle中是不可能的,因为它实现了多版本的读一致性。
在Oracle中,在上述情况下,当遇到用户B删除(并提交)行的块时,用户A的查询将使用撤消数据重构这些块在10:00时的样子——即用户A的查询开始的时间。
基本上就是这样——Oracle语句在数据库的某个版本上运行,就像它在单个时间点上存在一样。这个时间点几乎总是语句开始的时间。有些异常情况涉及到更新,此时该时间点将移动到时间点“MID语句”。但它总是在某个时间点上保持一致。