首页 > 代码库 > 转Rollback后undo到底做了些什么?

转Rollback后undo到底做了些什么?

转自:http://biancheng.dnbcw.info/oracle/309191.html

Rollbackundo到底做了些什么?

 

从概念上讲,undo正好与redo相对。当你对数据执行修改时,数据库会生成undo信息,这样万一你执行的事务或语句由于某种原因失败了,或者如果你用一条rollback语句请求回滚,就可以利用这些undo信息将数据还原到修改前的样子。Redo用于在失败时还原事务(即恢复事务),undo则用于取消一条语句或者一组语句的作用。与redo不同,undo在数据库内部存储在一组特殊的段中,这称为undo段(undo segment)。

 

通常对undo有一个误解,认为undo用于将数据库物理地恢复到执行语句或者事务之前的样子,但实际上并非如此。数据库只是逻辑地恢复到原来的样子,所有修改都被逻辑地取消,但数据结构以及数据库块本身在回滚后可能大不相同。原因在于:在所有的多用户系统中,可能会有数十、数百甚至数千个并发事务。数据库的主要功能之一就是协调对数据的并发访问。也许我们的事务在修改一些块,而一般来讲往往会有许多其他的事务也在修改这些块。因此,不能简单地将一个块放回到我们事务开始前的状态,这样会撤销其他人(其他事务)的工作!

 

例如,我们的事务执行一个insert语句,这条语句导致分配一个新区段(也就是说,导致表的空间增大)。通过执行这个insert,我们将得到一个新的块,格式化这个块以便使用,并在其中放上一些数据。此时,可能出现某个事务,他也向这个块中插入数据。如果要回滚我们的事务,显然不能取消对这个块的格式化和空间分配。因此,oracle回滚时,它实际上会做与先前逻辑上相反的工作。对于每个insert,oracle会完成一个delete。对于每个delete,oracle会执行一个insert。对于每个update,oracle则会执行一个“反update”,或者执行另一个update将修改的行放回去。当然这种undo生成对于直接路径操作(direct path operation)不适用,直接路径操作能够绕过表上的undo生成。

 

为了更好的说明问题,下面做一个小小的测试,以便验证上述的正确性。以下就是一个简单测试的步骤:

(1)      创建一个新的空表。

(2)      对它做一个全表扫描,观察对该表所执行的I/O数量。

(3)      向表中填入许多行(暂时不提交commit)

(4)      回滚这个工作。

(5)      再次进行全表扫描,观察对该表所执行的I/O数量。

 

好了,下面我们一起来做一个简单的测试工作:

首先,创建一个空表:

hongsy@test>create table t

  2  as

  3  select *

  4  from all_objects

  5  where 1=0;

 

表已创建。

 

hongsy@test>select * from t;

 

未选定行

 

        hongsy@test>set autotrace traceonly statistics

hongsy@test>select * from t;

 

未选定行

 

Statistics

----------------------------------------------------------

          0  recursive calls

          0  db block gets

          3  consistent gets

          0  physical reads

          0  redo size

        915  bytes sent via SQL*Net to client

        372  bytes received via SQL*Net from client

          1  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          0  rows processed

 

hongsy@test>set autotrace off

 

hongsy@test>insert into t select * from all_objects;

 

已创建31620行。

 

hongsy@test>rollback;

 

回退已完成。

 

hongsy@test>select * from t;

 

未选定行

 

hongsy@test>set autotrace traceonly statistics

hongsy@test>select * from t;

 

未选定行

 

Statistics

----------------------------------------------------------

          0  recursive calls

          0  db block gets

        436  consistent gets

          0  physical reads

          0  redo size

        915  bytes sent via SQL*Net to client

        372  bytes received via SQL*Net from client

          1  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

0    rows processed

 

前面的insert 导致将一些块增加到表的高水位线(high-water mark,HWM)之下,这些块没有因为rollback而消失,它们还在那里并且已经格式化,只不过现在为空。全表扫描必须读取这些块,看看其中是否包含行。通过比较上面对同一表查询的两个统计信息我们得出:undo操作只是回滚了数据库的逻辑结构,而没有撤销其物理结构。

 

以上是本人近期对undo的研究之一,写下自己的学习心得,供大家讨论。限于本人学识水平,难免存在问题,请批评指正。如有异议请email:hongsy@e-u.cn。

转Rollback后undo到底做了些什么?