首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > 其他数据库 >

undo表空间有关

2012-07-04 
undo表空间相关?DML语句与undo? 当我们发出一条DML(比如update t set col1B where col1A)语句时,其

undo表空间相关

?DML语句与undo?
当我们发出一条DML(比如update t set col1='B' where col1='A')语句时,其执行过程可大致概括为以下几步。
1、在shared pool里进行解析,从而生成执行计划。
假设根据执行计划,得出col1='A'的记录存放在10号数据文件的54号数据块里。
2、服务器进程在buffer cache里找一个可用的undo数据块,如果没有发现,则到undo表空间里找一个可用的undo块,并调入buffer cache。假设获得的undo数据块号为24号,位于11号undo数据文件里。
3、将改变前的值,也就是A放入11号undo数据块。
由于undo数据块发生了变化,于是产生重做记录,假设重做记录号为120。
行号? 事务id file# block# row? column? value
120? T1? 24? 11? 10? col1?? A?
4、在buffer cache里找到54号数据块。如果没有发现,则从10号数据文件里调入。
将改变后的值,也就是B放入54号数据块。
由于数据块发生了变化,于是产生重做记录,假设重做记录号为121。
行号? 事务id file# block# row? column? value
121? T1? 10? 54? 10? col1?? B??
5、控制权返回给用户,如果在SQL*Plus里执行DML,则表现为光标返回。
当用户发出commit命令时,触发LGWR进程,将120与121这两个重做记录写入联机日志文件,并将54号数据块和11号undo数据块头部所记录的事务状态标记设置为已提交。然后控制权返回给用户,如果在SQL*Plus里执行DML操作,则表现为光标返回。
6、这个时候,54号数据块以及11号undo块并不一定被DBWn写入数据文件。只有在脏数据块的数量达到一定程度才会被写入。
事务只要被提交或回滚,那么该事务所使用的undo块就可以被覆盖。对于上面的例子来说,当第 步,用户发出commit命令以后,11号undo块里的数据就可以被其他事务所覆盖。
undo的作用

在Oracle数据库中,undo主要有三大作用:提供一致性读(Consistent Read)、回滚事务(Rollback Transaction)以及实例恢复(Instance Recovery)。
一致性读是相对于脏读(Dirty Read)而言的。假设某个表T中有10000条记录,获取所有记录需要15分钟时间。当前时间为9点整,某用户A发出一条查询语句:select * from T,该语句在9点15分时执行完毕。当用户A执行该SQL语句到9点10分的时候,另外一个用户B发出了一条delete命令,将T表中的最后一条记录删除并提交了。
那么到9点15分时,A用户将返回多少条记录?
如果返回9999条记录,则说明发生了脏读;如果仍然返回10000条记录,则说明发生了一致性读。很明显,在9点钟那个时间点发出查询语句时,表T中确实有10000条记录,只不过由于I/O的相对较慢,所以才会花15分钟完成所有记录的检索。对于Oracle数据库来说,没有办法实现脏读,必须提供一致性读,并且该一致性读是在没有阻塞用户的DML的前提下实现的。
那么undo数据是如何实现一致性读的呢?还是针对上面的例子。用户A在9点发出查询语句时,服务器进程会将9点那个时间点上的SCN号记录下来,假设该SCN号为SCN9.00。那么9点整的时刻的SCN9.00一定大于等于记录在所有数据块头部的ITL槽中的SCN号(如果有多个ITL槽,则为其中最大的那个SCN号)。
服务器进程在扫描表T的数据块时,会把扫描到的数据块头部的ITL槽中的SCN号与SCN9:00之间进行比较,哪个更大。如果数据块头部的SCN号比SCN9.00要小,则说明该数据块在9点以后没有被更新,可以直接读取其中的数据;否则,如果数据块ITL槽的SCN号比SCN9.00要大,则说明该数据块在9点以后被更新了,该块里的数据已经不是9点那个时间点的数据了,于是要借助undo块。
9点10分,B用户更新了表T的最后一条记录并提交(注意,在这里,提交或者不提交并不是关键,只要用户B更新了表T,用户A就会去读undo数据块)。假设被更新记录属于N号数据块。那么这个时候N号数据块头部的ITL槽的SCN号就被改为SCN9.10。当服务器进程扫描到被更新的数据块(也就是N号块)时,发现其ITL槽中的SCN9.10大于发出查询时的SCN9.00,说明该数据块在9点以后被更新了。于是服务器进程到N号块的头部,找到SCN9.10所在的ITL槽。由于ITL槽中记录了对应的undo块的地址,于是根据该地址找到undo块,将undo块中的被修改前的数据取出,再结合N号块里的数据行,从而构建出9点10分被更新之前的那个时间点的数据块内容,这样的数据块叫做CR块(Consistent Read)。对于delete来说,其undo信息就是insert,也就是说该构建出来的CR块中就插入了被删除的那条记录。随后,服务器进程扫描该CR块,从而返回正确的10000条记录。
让我们继续把问题复杂化。假设在9点10分B用户删除了最后一条记录并提交以后,紧跟着9点11分,C用户在同一个数据块里(也就是N号块)插入了2条记录。这个时候Oracle又是如何实现一致性读的呢(假设表T的initrans为1,也就是只有一个ITL槽)?因为我们已经知道,事务需要使用ITL槽,只要该事务提交或回滚,该ITL槽就能够被重用。换句话说,该ITL槽里记录的已经是SCN9.11,而不是SCN9.10了。这时,ITL槽被覆盖了,Oracle的服务器进程又怎能找回最初的数据呢?
其中的秘密就在于,Oracle在记录undo数据的时候,不仅记录了改变前的数据,还记录了改变前的数据所在的数据块头部的ITL信息。因此,9点10分B用户删除记录时(位于N号块里,并假设该N号块的ITL信息为[Undo_block0 / SCN8.50]),则Oracle会将改变前的数据(也就是insert)放到undo块(假设该undo块地址为Undo_block1)里,同时在该undo块里记录删除前ITL槽的信息(也就是[Undo_block0 / SCN8.50])。删除记录以后,该N号块的ITL信息变为 [Undo_block1 / SCN9.10];到了9点11分,C用户又在N号块里插入了两条记录,则Oracle将插入前的数据(也就是delete两条记录)放到undo块(假设该undo块的地址为Undo_block2)里,并将9点11分时的ITL槽的信息(也就是[Undo_block1 / SCN9.10])也记录到该undo块里。插入两条记录以后,该N号块的ITL槽的信息改为 [Undo_block2 / SCN9.11]。
那么当执行查询的服务器进程扫描到N号块时,发现SCN9.11大于SCN9.00,于是到ITL槽中指定的Undo_block2处找到该undo块。发现该undo块里记录的ITL信息为[Undo_block1 / SCN9.10],其中的SCN9.10仍然大于SCN9.00,于是服务器进程继续根据ITL中记录的Undo_block1,找到该undo块。发现该undo块里记录的ITL信息为[Undo_block0 / SCN8.50],这时ITL里的SCN8.50小于发出查询时的SCN9.00,说明这时undo块包含合适的undo信息,于是服务器进程不再找下去,而是将N号块、Undo_block2以及Undo_block1的数据结合起来,构建CR块。将当前N号的数据复制到CR块里,然后在CR块里先回退9点11分的事务,也就是在CR块里删除两条记录,然后再回退9点10分的事务,也就是在CR块里插入被删除的记录,从而构建出9点钟时的数据。Oracle就是这样,以层层嵌套的方式,查找整个undo块的链表,直到发现ITL槽里的SCN号小于等于发出查询时的那个SCN号为止。正常来说,当前undo块里记录的SCN号要比上一个undo块里记录的SCN号要小。

???????? undo表空间有关
但是在查找的过程中,可能会发现当前undo块里记录的ITL槽的SCN号比上一个undo块里记录的SCN号还要大。这种情况说明由于事务被提交或回滚,导致当前找到的undo块里的数据已经被其他事务覆盖了,于是我们无法再找出小于等于发出查询时的那个时间点的SCN号,这时Oracle就会抛出一个非常经典的错误——ORA-01555,也就是snapshot too old的错误。

回滚事务则是在执行DML以后,发出rollback命令撤销DML所作的变化。Oracle利用记录在ITL槽里记录的undo块的地址找到该undo块,然后从中取出变化前的值,并放入数据块中,从而对事务所作的变化进行回滚。
实例恢复则是在SMON进程完成前滚并打开数据库以后发生。SMON进程会去查看undo segment头部(所谓头部就是undo segment里的第一个数据块)记录的事务表(每个事务在使用undo块时,首先要在该undo块所在的undo segment的头部记录一个条目,该条目里记录了该事务相关的信息,其中包括是否提交等),将其中既没有提交也没有回滚,而是在实例崩溃时被异常终止的事务全部回滚。

关于UNDO_RETENTION

UNDO_RETENTION通常默认是900 秒,也就是15 分钟。值得注意是,undo_retention 只是指定undo 数据的过期时间,并不是说,undo 中的数据一定会在undo表空间中保存15 分钟,比如说刚一个新事务开始的时候,如果undo 表空间已经被写满,则新事务的数据会自动覆盖已提交事务的数据,而不管这些数据是否已过期。因此,当你创建一个自动管理的undo 表空间时,还要注意其空间大小,要尽可能保证undo 表空间有足够的存储空间。
同时还要注意,也并不是说,undo_retention 中指定的时间一过,已经提交事务中的数据就立刻无法访问,它只是失效,只要不被别的事务覆盖,它会仍然存在,并可随时被flashback 特性引用。如果你的undo表空间足够大,而数据库又不是那么繁忙,那么其undo_retention 参数的值并不会影响到你,哪怕你设置成1,只要没有事务去覆盖undo 数据,它就会持续有效。因此呢,这里还是那句话,要注意undo 表空间的大小,保证其有足够的存储空间。因此如果闪回表时所需要的UNDO数据,由于保留的时间超过了UNDO_RETENTION的所指定的值,从而导致该UNDO数据被其他事务覆盖的话,那么就不能闪回到指定时间了。表空间上指定了retention guarantee选项使UNDO数据在一定时间内不被覆盖。

修改UNDO_RETETION的值命令如下:

SQL> alter system set undo_retention=600 scope=both;

启用undo guarantee

SQL> alter tablespace undotbs1 retention guarantee;

禁用undo guarantee

SQL> alter tablespace undotbs1 retention noguarantee;
在AUM模式下,当活动的事务使用undo segment时,事务可以在不同的undo segment之间动态交换undo空间,也就是在不同的undo segment里交换extents。当一个正在执行的事务需要更多的undo空间时,首先会重用当前undo segment里的可用空间;如果当前undo segment里的可用空间(也就是extents)不足时,则会按照下面的步聚获得所需要的extent:
获取undo表空间里可用的、空的extents;
获取其他undo segment里的expired状态的extents;
如果undo表空间里的数据文件启用了自动扩展(autoextend on),则数据文件进行自动扩展;
如果undo表空间里的数据文件没有启用自动扩展,则获取其他undo segment里的INACTIVE状态的extents;
如果以上步骤均无法获得可用空间时,报空间不足的错误消息。

管理undo

数据库中可以同时存在多个undo表空间,但是在一个时间点上,数据库只能使用一个undo表空间。如果我们将undo_tablespace参数设置为另外一个undo表空间的名字,则这叫做undo表空间的切换。
当我们切换undo_tablespace时,如果旧的undo表空间上有事务正在执行,则该旧的undo表空间变成pending offline状态。同时用户的事务可以正常执行,切换操作立刻结束,它并不会等待使用旧的undo表空间的事务结束。发生切换以后,所有新的事务所产生的undo数据不会存放在该旧的undo表空间里,而是会使用新的undo表空间。我们不能使用pending offline状态的undo表空间,该状态下的undo表空间也不能被删除。最终,当旧的undo表空间上的所有的事务都提交以后,旧的undo表空间从pending offline状态变成offline状态,这时我们才可以删除该旧的undo表空间。
在删除undo表空间时,与删除一般的表空间不同。也就是说,如果drop tablespace后面跟的是某个undo表空间的名字,就相当于发出drop tablespace ? including contents命令。一个undo 表空间只有在当前没有被活动的事务使用的时候才能被删除。如果undo表空间还包含某个未结束的事务,比如某个事务异常中断,但是还没有回滚,这时drop tablespace会报错。但是,drop tablespace命令能够删除那些含有inactive状态的undo块(这些undo块还没有expired)的undo表空间。这样就有可能发生ORA-1555错。因此,我们在切换undo_tablespace以后,应该在等待的时间超过undo_retention的长度以后再删除旧的undo表空间。

在判断undo表空间应该设置多大时,借助Database Control所提供的Undo Advisory会更加简单。这里,横轴为undo retention,以秒为单位,纵轴为undo表空间大小尺寸,以MB为单位。


?

参考至:《教你成为10g OCP》韩思捷著

如有错误,欢迎指正

邮箱:czmcj@163.com

热点排行