转Rollback后undo到底做了些什么?
转自:http://biancheng.dnbcw.info/oracle/309191.html
Rollback后undo到底做了些什么?
从概念上讲,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到底做了些什么?的更多相关文章
- linux内核中宏likely和unlikely到底做了些什么?
1. 先看看它们长啥样吧!(它们有两种定义,第一种是使能了程序trace功能的宏定义,第二种是普通的宏定义,咱们分析普通宏定义吧) # define likely(x) __builtin_expec ...
- js中的new()到底做了些什么??
要创建 Person 的新实例,必须使用 new 操作符.以这种方式调用构造函数实际上会经历以下 4个步骤:(1) 创建一个新对象:(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新 ...
- Java环境的搭建及用记事本来揭露下JDK到底做了些什么
和我一样的新手想学Java就从自己搭建环境开始,请看完这边文章,我搜集资料的整合. Java的标准版本是Java SE,所说的JDK(Java Development Kits)就是Java SE的开 ...
- iOS 中push和pop到底系统做了些什么事
iOS中的push和pop是一个很常用的视图切换方法,他们是成对出现的, 简而言之,push就是压栈,pop就是出栈! [self.navigationController pushViewContr ...
- AFNetworking到底做了什么
写在开头: 作为一个iOS开发,也许你不知道NSUrlRequest.不知道NSUrlConnection.也不知道NSURLSession...(说不下去了...怎么会什么都不知道...)但是你一定 ...
- AFNetworking到底做了什么?(二)
接着上一篇的内容往下讲,如果没看过上一篇内容可以点这: AFNetworking到底做了什么? 之前我们讲到NSUrlSession代理这一块: 代理8: /* task完成之后的回调,成功和失败 ...
- dreamvc框架(三),dispartcher做了些什么
这一篇我会介绍一些dreamvc的核心类Dispatcher都做了些什么,首先我们先来看一看init方法,这是在DispatcherServlet和DispatcherFilter里面都会调用到的一个 ...
- 转 OGG add trandata 到底做了什么
有的时候我们做OGG的时候add trandata会出现异常. 这里就剖析一下add trandata到底做了什么 GGSCI (yjfora81 as ggs_admin@testdb) 2> ...
- vue.js中,input和textarea上的v-model指令到底做了什么?
v-model是 vue.js 中用于在表单表单元素上创建双向数据绑定,它的本质只是一个语法糖,在单向数据绑定的基础上,增加了监听用户输入事件并更新数据的功能: 对,它本质上只是一个语法糖,但到底是一 ...
随机推荐
- android 控件自定义样式
一.按钮(Button) 方式1.存在.9图片或图片时 可在drawable文件夹下新建xml文件style_button_one.xml,代码如下 <?xml version=" ...
- laravel 添加第三方扩展库
确定需要安装的位置 common.php测试代码 打开cmd 跳转到项目根目录下运行命令 composer install 打开文件 vender/composer/autoload_classmap ...
- js onblur 和 onkeyup 事件用法
1. onblur 表示失去焦点时触发 2. onkeyup 表示键盘每输完一个字符之后触发,就是键盘上的按键被放开时. 例子如下: <!DOCTYPE HTML PUBLIC "-/ ...
- 《C++反汇编与逆向分析技术揭秘》——函数的工作原理
各种调用方式的考察 示例: cdecl方式是调用者清空堆栈: 如果执行的是fastcall: 借助两个寄存器传递参数: 参数1和2借助局部变量来存储: 返回值 如果返回值是结构体: 返回值存放在eax ...
- 从后台调用前台js
引用: using System.Web.UI; ScriptManager.RegisterClientScriptBlock(this, GetType(), "Js", &q ...
- linux upstart启动配置
程序名.conf放在/etcc/init/目录下# 注释 description "your-server" author "xxx" start on run ...
- 修改LibreOffice Draw中定义的样式名称
目前我使用的是LibreOffice 4.2.4.2.经过以往的测试和使用经验,这是诸多版本中较为稳定和bug相对较少的.今天无意中发现该版本的LibreOffice Draw存在一个问题:样式名称修 ...
- reposync 同步yum仓库
reposync 同步远程yum仓库到本地 OPTIONS -h, --help 显示帮助 -c CONFIG, --config=CONFIG ...
- easyui datagrid分页
datagrid分页设置 pagination="true" 貌似是不行的! 只是显示分页工具栏 没有达到分页效果 前端 $(function (){ var p = $('#d ...
- Java版冒泡排序和选择排序
一.理解说明 1.理解和记忆 冒泡排序:依次定位数组元素,每次只和相邻的且符合条件的元素交换位置. 选择排序:依次在数组的每个位置,通过逐个对比选择出最大或最小的元素. 2.知识点说明 (1)数组是引 ...