一文看懂oracle数据库UNDO表空间是如何设计的
sinye56 2024-09-16 14:28 6 浏览 0 评论
概述
今天主要分享UNDO的一些作用及oracle是如何去设计并管理它的,大家一起看下吧~
01
UNDO的作用
1、作用
还原段的引入,主要是为了解决三个问题。
事务恢复:在进行DML操作时,insert、update、delete操作时,undo段记录事务的反向操作并且redo日志也记录undo段的操作,既redo保护undo段的信息。当实例关闭或意外崩溃后,再次open时实例需要对没有commit的事务进行回滚,完成事务的恢复。
事务回滚:用户进行DML操作后没有进行commit,需要修改前的数据。只要该操作在undo段保护的时间内,此时执行rollback操作可以回滚到最近记录点或上一次commit操作后的状态,恢复到数据修改前的状态。
读一致性:当进行DML操作时,undo段会记录数据变更前的状态(通过构造原数据的一致性数据块)。如果用户还没有进行commit操作,其他人查询此条数据会看到数据变更前的状态。因为其他用户读到的数据是undo段中原数据块中的数据,保证没有commit的数据读取的一致性。
2、读一致性
下面模拟复杂环境下,读一致性在复杂环境下如何能够保证?
1)会话A在9:50分的时候对T表发起了一次查询,需要10分钟完成查询结果打印。
2)会话B在9:51分对T表进行了一次update,并且commit。此时undo段会记录会话B在update的反向操作,假设名为undo1。
3)会话C在9:52分对T表进行了一次insert,并且同样commit。此时undo段会记录insert反向操作,假设名为undo2。
4)会话A的查询在发起时已经记录数据库当前的SCN号,假设此时SCN号为950。由于ILT事务槽记录最新的SCN号,所以再与数据块头部ILT事务槽中的SCN号进行比对时发现当前SCN大于950,所以需要对undo段进行查询。查询到undo2段信息进行比对发现SCN大于950,通过undo中记录的事务信息在进行前一个数据变更查找,此时undo1的SCN还是大于950,再继续查找前面的undo信息,发现undo0的SCN号比950要早,此时会将undo0记录的数据的信息+未变更的数据块信息打印给用户。
5)由于undo段是通过覆盖的方式进行记录的,如果时间过长或频繁进行DML操作。那么在寻找过程中可能会出现没有小于SCN号950的undo段,会返回一个经典错误ORA-1555 snapshoot too old(快照过旧),这样是为了避免幻影读、脏读等现象,保证读一致性的绝对特性。
通过上面的一个模拟,证明undo段不仅记录事务的回滚信息、同样记录ILT事务槽的上一次变更信息,并且保证能够通过不断读取undo段中记录ILT事务槽中的SCN号进行事务的历史查询。简单来讲只要UNDO段足够大,数据库中任何时间的DML操作都可以进行查询。
读一致性的具体步骤
- 确认读取时间的SCN号
- 搜索所有关联此表、行的数据块,要求数据块ILT事务槽的SCN号要小于读取时刻的SCN号。
- 如果搜索到小于读取时刻的SCN号,直接读取
- 如果全部没有小于读取时刻的SCN号,则根据数据块内ILT事务槽记录的undo信息,查找改变之前的数据。如果SCN号还是大于读取时刻,那么通过递归读取undo块所有关联这一事务的数据块,直至找到比读取时刻SCN号小undo块的信息,找到后进行读取。
- 如果没有比读取时刻的SCN号小的undo信息,那么报ORA-155错误。
3、实例恢复与事务回滚解析
实例恢复:在需要实例恢复时,oracle会读取UNDO段的头部信息的事务表,每一个事务是否commit的信息都会存储在事务表内。已经commit的事务不作处理,没有commit的事务会进行rollback的回滚处理完成事务回滚。防止脏数据的写入,造成脏读。
事务回滚:当需要回滚事务时,由于错误或者rollback命令都会产生回滚需求。此时根据ITL槽中记录的undo数据块地址找到undo块,进行数据的反向操作,从而实现恢复数据,即回滚事务。
02
UNDO参数的解析
1、UNDO_MANAGEMENT
该初始化参数用于指定UNDO数据的管理方式.如果要使用自动管理模式,必须设置该参数为AUTO,如果使用手工管理模式,必须设置该参数为MANUAL,使用自动管理模式时,oracle会使用undo表空间管理undo管理,使用手工管理模式时,oracle会使用回滚段管理undo数据,如果使用自动管理模式时,如果没有配置初始化参数UNDO_TABLESPACE。Oracle会自动选择第一个可用的UNDO表空间存放UNDO数据,如果没有可用的UNDO表空间,oracle会使用SYSTEM回滚段存放UNDO记录,并在ALTER文件中记载警告.
2、UNDO_TABLESPACE
该初始化参数用于指定例程所要使用的UNDO表空间,使用自动UNDO管理模式时,通过配置该参数可以指定实例所要使用的UNDO表空间.
在RAC(Real Application Cluster)结构中,因为一个UNDO表空间不能由多个实例同时使用,所有必须为每个实例配置一个独立的UNDO表空间.
3、undo_retention参数
在oracle 10g开始引入undo_retention参数,该参数是一个时间值。说明当还原段中的事务在提交后继续保留的时间,为flashback等工具进行如闪回数据等操作,该参数默认值为900秒,可以动态修改。
该参数以秒为单位,表示当事务提交或回滚以后,该事务所使用undo块里的数据能够提供的保留时间。当保留时间超过undo_retention所指定的时间以后,该undo块才能够被其他事务覆盖。当我们使用AUM的时候,并且设置了undo_retention以后,undo块的状态就会存在如下4种情况。
- active:活跃的,表示正在使用该数据块的事务还没有提交或回滚。
- inactive:不活跃的,表示该数据块上没有活动的事务,该状态的数据块可以被其他事务覆盖。
- expired:达到时间上限的,表示该数据块持续inactive的时间已经超过了undo_retention所指定的时间,如果没有freed、inactive可以被其他事务覆盖。
- freed:已经释放的,表示该数据块是空的,从来没有使用过。
在自动管理模式中,事务可以在不同的undo segment之间动态交换undo空间,也就是在不同的undo segment里交换extents。
当一个事务需要更多的undo空间的时候,如何进行处理?
当事务进行DML操作需要undo段进行事务保护时,首先获取undo表空间里可用的、空的extents(segment的最小分配单位是extent),获取其他undo segment里的expired状态的extents。
如果undo表空间内的数据文件启动了autoextensible(自动拓展),则数据文件会进行自动拓展。如果没有启动自动拓展,则获取undo segment里处于inactive状态的extent,如果没有此种状态的,会报ORA-30036(undo无法继续拓展)。
undo表空间获取空间的申请顺序
freed=>expired=>自动拓展(必须该参数为yes状态才可以)=>inactive(下面详细解释此种状态的覆盖)=>ORA-30036
而且在使用数据块时尽量使用相对更短的连续extent,如不足时才使用更连续的extent。这样能够减少碎片的产生。并且尽量不去覆盖inactive状态的数据块,如果空间足够会最大限度的保存此种状态的数据块包含的信息。
03
UNDO段的分类
1、分类
oracle中还原段共包含两大类,系统还原段和非系统还原段。
系统还原段为系统表空间使用,当系统表空间中的对象发生变化时,这些对象的原始值就保存在系统还原段中,系统还原段在系统表空间中创建,可以在自动模式和手动模式中。
非系统还原段为非系统表空间如用户表空间等所使用,当一个数据库系统具有非系统表空间时,就需要至少一个非系统还原段或一个自动管理的还原表空间,其中自动管理模式由数据库服务器自动维护,但需要至少一个还原表空间,而手动管理模式需要管理员创建非系统还原段,这些手动的非系统还原段分为两种类型,即公有还原段和私有还原段。
Oracle 9i以上版本都实现了还原段的自动管理,使用自动管理需要首先创建一个还原表空间,并通过还原表空间告诉数据库服务器,之后的管理工作都由数据库服务器自动完成。
2、还原段的自动管理
这里只涉及私有还原段的管理,即单实例UNDO段自动管理
在oracle 11g中通过两个参数来设置还原段的自动管理:
UNDO_MANAGEMENT(还原段的管理方式):此参数为静态参数需要设置后重启数据库才能生效。
UNDO_TABLESPACE(还原表空间的名字):此参数为动态参数设置完成可在数据库启动状态生效。
04
利用dba_undo_extents数据字典中查找undo段记录的原数据
该数据字典记录所有undo表空间记录undo段的分配信息,包括记录表空间的名字、段、区段、数据文件ID、数据块ID、retention保留状态等信息。
1、创建T表插入一行数据
create table t (id number,name varchar2(10)); insert into t values (1,'hwb');
2、查询此条更新记录回滚段的名字
select a.username,b.name,c.used_ublk from v$session a,v$rollname b,v$transaction c where a.saddr=c.ses_addr and b.usn=c.xidusn;
- v$session:记录用户关于会话信息
- v$rollname:记录回滚段的名字
- v$transaction:记录关于事务的信息
3、通过查询到的回滚段名字,查询该回滚段在所在表空间、区段等信息
select segment_name,tablespace_name,extent_id from dba_undo_extents where segment_name='_SYSSMU3_2097677531