UNDO表空间的作用和管理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qqww120102/article/details/77994066

UNDO表空间管理
一、UNDO的作用
还原段的引入,主要是为了解决三个问题。
事务恢复: 在进行DML操作时,insert、update、delete操作时,undo段记录事务的反向操作并且redo日志也记录undo段的操作,既redo保护undo段的信息。当实例关闭或意外崩溃后,再次open时实例需要对没有commit的事务进行回滚,完成事务的恢复。
事务回滚: 用户进行DML操作后没有进行commit,需要修改前的数据。只要该操作在undo段保护的时间内,此时执行rollback操作可以回滚到最近记录点或上一次commit操作后的状态,恢复到数据修改前的状态。
读一致性: 当进行DML操作时,undo段会记录数据变更前的状态(通过构造原数据的一致性数据块)。如果用户还没有进行commit操作,其他人查询此条数据会看到数据变更前的状态。因为其他用户读到的数据是undo段中原数据块中的数据,保证没有commit的数据读取的一致性。

下面模拟复杂环境下,读一致性在复杂环境下如何能够保证

会话A在9:50分的时候对T表发起了一次查询,需要10分钟完成查询结果打印。会话B在9:51分对T表进行了一次update,并且commit。此时undo段会记录会话B在update的反向操作,假设名为undo1。会话C在9:52分对T表进行了一次insert,并且同样commit。此时undo段会记录insert反向操作,假设名为undo2。会话A的查询在发起时已经记录数据库当前的SCN号,假设此时SCN号为950。由于ILT事务槽记录最新的SCN号,所以再与数据块头部ILT事务槽中的SCN号进行比对时发现当前SCN大于950,所以需要对undo段进行查询。查询到undo2段信息进行比对发现SCN大于950,通过undo中记录的事务信息在进行前一个数据变更查找,此时undo1的SCN还是大于950,再继续查找前面的undo信息,发现undo0的SCN号比950要早,此时会将undo0记录的数据的信息+未变更的数据块信息打印给用户。由于undo段是通过覆盖的方式进行记录的,如果时间过长或频繁进行DML操作。那么在寻找过程中可能会出现没有小于SCN号950的undo段,会返回一个经典错误ORA-1555 snapshoot too old(快照过旧),这样是为了避免幻影读、脏读等现象,保证读一致性的绝对特性。

通过上面的一个模拟,证明undo段不仅记录事务的回滚信息、同样记录ILT事务槽的上一次变更信息,并且保证能够通过不断读取undo段中记录ILT事务槽中的SCN号进行事务的历史查询。简单来讲只要UNDO段足够大,数据库中任何时间的DML操作都可以进行查询。

读一致性的具体步骤
1、确认读取时间的SCN号
2、搜索所有关联此表、行的数据块,要求数据块ILT事务槽的SCN号要小于读取时刻的SCN号。
3、如果搜索到小于读取时刻的SCN号,直接读取
4、如果全部没有小于读取时刻的SCN号,则根据数据块内ILT事务槽记录的undo信息,查找改变之前的数据。如果SCN号还是大于读取时刻,那么通过递归读取undo块所有关联这一事务的数据块,直至找到比读取时刻SCN号小undo块的信息,找到后进行读取。
5、如果没有比读取时刻的SCN号小的undo信息,那么报ORA-155错误。

实例恢复与事务回滚解析
实例恢复:在需要实例恢复时,oracle会读取UNDO段的头部信息的事务表,每一个事务是否commit的信息都会存储在事务表内。已经commit的事务不作处理,没有commit的事务会进行rollback的回滚处理完成事务回滚。防止脏数据的写入,造成脏读。
事务回滚:当需要回滚事务时,由于错误或者rollback命令都会产生回滚需求。此时根据ITL槽中记录的undo数据块地址找到undo块,进行数据的反向操作,从而实现恢复数据,即回滚事务。

UNDO segment的选择算法
事务发生DML操作时, 服务器进程 会选择一个undo segment,具体算法如下:
1、首先尝试将每一个空闲undo segment绑定一个事务,每个undo segment只能绑定一个事务。
2、如果发现没有空闲的undo segment,所有的undo segment都与事务绑定。
3、此时系统尝试将脱机的undo segment联机
4、如果没有可用的undo segment进行联机,则会尝试创建一个新的undo segment
5、如果上面几个步骤都没有成功(没有可以绑定的undo段,并且没有脱机的undo段,而且没有可用空间不能创建新的undo段),算法会尝试寻找最早使用的undo segment。这种情况下,不同的多个事务会在同一个undo segment里同时进行。
6、每隔12个小时会由SMON进程检查一次,删除那些idle(闲置)状态的extent
7、DML操作需要使用undo段时,发现空间不足时,会唤醒SMON进程进行一次检查将undo segment里面暂时使用的extent拿过了使用。
二、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: 已经释放的,表示该数据块是空的,从来没有使用过。

在AUM(自动管理)模式中,事务可以在不同的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状态的数据块,如果空间足够会最大限度的保存此种状态的数据块包含的信息。

数据查询出现ORA-1555的原因,和如何避免出现?
ORA-1555错误的出现,共有两种原因。
首先解释一下Oracle在数据变更后,如何保证原始数据能够在变更数据不提交的情况下如何得到保护。
原始数据已经被update、delete等DML操作,但变更数据还未进行commit,此时Oracle通过UNDO段构造与原数据相同的一致性数据块,保证其他用户数据不会出现脏读。但在commit后该事务占用的回滚段事务状态会被标记为不活跃的(inactive),回滚段中此区段可以被覆盖重用。
1、回滚段数据被覆盖
出现原因:通过前面讲到的内容那么一个问题就出现了,如果一个查询需要使用已经变更为inactive并且被覆盖的回滚段一致性读块内的数据,想实现一致性读,那么此时就会出现Oracle著名的ORA-01555错误。原因有SQL语句执行时间太长、UNDO表空间过小、事务量过大,提交过于频繁,导致执行SQL过程中进行一致性读时,修改的原数据(UNDO数据)在UNDO表空间中已经被覆盖,不能构造一致性读块。
避免出现的方法:尽量加大回滚段的容量,尽量将undo_retention参数内的提交后保留时间设置更大一些 如果需要保证原数据在retention保留时间内 绝对 能够查找,那么在保证回滚段容量足够用的前提下可以将表空间参数中加入retention guarantee以保证原数据的不被任何情况的覆盖。优化出错的SQL和尽量将大事务分割成小事务,并且不进行频繁的提交。
2、块延时清除(Delayed Block Cleanout)引起ORA-1555
出现原因:相比第一种,这种出现的几率11g会低很多首先简单解释一下块延时清除的原理和目的。
块延时清除是oracle一种为了提高commit速度的机制。清除的是数据块ITL事务槽内有关“提交”的事务信息,oracle在事务相关的提交列表中,记录已变更数据的数据块列表,每个列表20个块,根据事务需要分配多个列表。列表内有一个事务变更上限(10%),如果一次数据变更小于上限,并且数据块都在内存还未写入磁盘,则commit时清除数据块上的事务信息并且更新ITL内的commit scn为当前系统SCN。如果一次数据变更超过上限或者数据已经由于CKPT触发DBWn写等原因由DBWn写入磁盘上(即脏写),则commit不变更事务信息同时也不更新commit SCN。当进行select查询数据的时候,如果数据块上已经清除过事务信息,并且存在完整的commit scn可以让数据库判断数据是否需要回滚,那么就可以返回查询结果。
如果ITL内没有清除事务状态或者commit SCN信息不完整,数据库无法判断是否需要回滚。此时会在UNDO段中查找数据的原始信息,并清除数据块的事务信息并更新commit SCN为UNDO段原数据的SCN并通过DBWn写入数据块内,之后查询都直接通过数据块内的ITL进行确定数据是否需要回滚。
但是如果最近一次变更与查询间隔时间过长、间隔中进行过大量事务变更或频繁进行事务提交,造成undo段中的数据已经被覆盖,无法判断数据的变更情况和提交时间。此时oracle会查将该数据块中ITL事务信息清除并将commit SCN变更为回滚段中最老的事务,即最小的SCN号。以便保证数据能够查询,此时会报ORA-1555错误。
简单来讲下面写的就是查询数据时发生的块延时清除引起ORA-1555情况
如果当一个查询触发延迟块清除的时候,ORACLE 需要去查询回滚段获得该事务提交的SCN,如果事务前镜像信息已经被覆盖,并且查询的SCN小于回滚段记录中记录的最小提交SCN信息,那么oracle将无法判断查询的scn和事物提交scn的大小.则将commit 标记为 回滚段中所能找到的最小 scn(对于查询安全)。
undo_retention不绝对保证能够达到指定参数的时长?retention guarantee参数的作用?
默认情况下,oracle每隔30秒就会收集一次统计信息进行调整(怀疑由SMON进程进行收集),收集的信息包含运行时间最长的查询和产生undo的速度。通过设置undo_retention为0,可以使用AUM自动调整工具。而且以900秒为最低值,如果设置了具体时间,就不再支持动态调整undo_retention。
如果undo_retention为0,则实例会获取运行时间最长的那个查询所需要的时间。例如最长的查询为N秒,然后undo信息同样会保留N秒。当undo表空间尺寸太小时,发现不能保证这条最长的查询,则尽可能的利用现有空间让undo保留的时间尽可能长。并不会立即拓展undo数据文件,除非要覆盖undo信息在900秒以内发生的,才会拓展数据文件。
但如果undo表空间没有设置retention guarantee参数的情况下,并不能保证指定的保留时间内绝对不会被覆盖。一个会话执行多个事务或者多个会话在执行多个事务时。当commit之后undo_retention参数会保护数据在指定时间内可以查询,但此时新的DML 事务操作需要新的extent,可是如果没有空间分配和不能进行自动拓展的情况下,此时会将inactive状态的数据块覆盖。但是创建或修改表空间将retention guarantee参数添加后,再找不到新的extent时也不会去覆盖已经指定retention guarantee参数的undo表空间,此参数可以在dba_tablespace字典表retention内查询。

如何更改undo_retention参数
查询当前参数的时间,直接查询可以,也可以通过v$parameter数据字典参数表直接查询
SQL> show parameter undo_retention;

NAME TYPE VALUE
------------------ ------------- ---------
undo_retention integer 900
设置为1200秒
SQL> alter system set undo_retention = 1200;

System altered.
再次查询
SQL> show parameter undo_retention;

NAME TYPE VALUE
------------------ ------------- ------------
undo_retention integer 1200

三、UNDO段的分类
oracle中还原段共包含两大类,系统还原段和非系统还原段。
系统还原段为系统表空间使用,当系统表空间中的对象发生变化时,这些对象的原始值就保存在系统还原段中,系统还原段在系统表空间中创建,可以在自动模式和手动模式中。
非系统还原段为非系统表空间如用户表空间等所使用,当一个数据库系统具有非系统表空间时,就需要至少一个非系统还原段或一个自动管理的还原表空间,其中自动管理模式由数据库服务器自动维护,但需要至少一个还原表空间,而手动管理模式需要管理员创建非系统还原段,这些手动的非系统还原段分为两种类型,即公有还原段和私有还原段。

Oracle 9i以上版本都实现了还原段的自动管理,使用自动管理需要首先创建一个还原表空间,并通过还原表空间告诉数据库服务器,之后的管理工作都由数据库服务器自动完成。
还原段的自动管理
本次只涉及私有还原段的管理,即单实例UNDO段自动管理
在oracle 11g中通过两个参数来设置还原段的自动管理:
UNDO_MANAGEMENT(还原段的管理方式):此参数为静态参数需要设置后重启数据库才能生效。
UNDO_TABLESPACE(还原表空间的名字):此参数为动态参数设置完成可在数据库启动状态生效。

创建UNDO表空间

SQL> create undo tablespace test_undo_20170908
2 datafile '/u01/app/oracle/oradata/dg1/test_undo_20170908.dbf'
3 size 100m
4 autoextend on;

Tablespace created.

SQL> select tablespace_name,extent_management,contents,logging,status
2 from dba_tablespaces
3 where tablespace_name='TEST_UNDO_20170908';

TABLESPACE_NAME EXTENT_MAN CONTENTS LOGGING STATUS
------------------------------ ----------------- ------------------ --------------- -------------
TEST_UNDO_20170908 LOCAL UNDO LOGGING ONLINE

SQL> select file_name,file_id,bytes/(1024*1024) M,autoextensible
2 from dba_data_files
3 where tablespace_name='TEST_UNDO_20170908';

FILE_NAME FILE_ID M AUTOEXTENSIBLE
------------------------------------------------------------ ---------- -------------- ------------------
/u01/app/oracle/oradata/dg1/test_undo_20170908.dbf 15 100 YES

具体语法看之前表空间语法部分,创建了一个100MB的undo表空间已经联机,管理方式为本地管理,已经受到日志保护,并且空间不足时自动增长空间。
创建undo表空间需要具有DBA权限

维护UNDO表空间
维护undo表空间包括:重命名、增加数据文件、数据文件设置offline或online等
一、UNDO表空间重命名
undo表空间重命名:使用rename命令,下面测试修改非系统UNDO表空间TEST_UNDO和系统UNDO表空间UNDOTBS1

修改非系统默认UNDO表空间
查询表空间的名字
SQL> select tablespace_name,status,contents from dba_tablespaces
2 where tablespace_name='TEST_UNDO%';

TABLESPACE_NAME STATUS CONTENTS
------------------------------ --------- ---------
TEST_UNDO ONLINE UNDO

SQL> alter tablespace test_undo
2 rename to test_undo_two;

Tablespace altered.
非系统默认UNDO表空间修改后立即生效
SQL> select tablespace_name,status,contents from dba_tablespaces
2 where tablespace_name='TEST_UNDO%';

TABLESPACE_NAME STATUS CONTENTS
------------------------------ --------- ------------
TEST_UNDO_TWO ONLINE UNDO

下面修改系统默认UNDO表空间
SQL> alter tablespace undotbs1
2 rename to undo_num_one;

SQL> show parameter undo

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_management string AUTO
undo_retention integer 1200
undo_tablespace string UNDOTBS1
系统默认undo表空间修改后需要重启才能生效
SQL> shutdown immediate;

SQL> show parameter undo

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_management string AUTO
undo_retention integer 1200
undo_tablespace string UNDO_NUM_ONE

二、向UNDO表空间添加数据文件
查询TEST_UNDO_TWO表空间大小
SQL> select tablespace_name,file_name,bytes/(1024*1024) M,autoextensible
2 from dba_data_files
3 where tablespace_name='TEST_UNDO_TWO';

TABLESPACE_NAME FILE_NAME M AUTOEXTENSIBLE
------------------------------ ------------------------------------------------------------ --------------- -----------------------------------
TEST_UNDO_TWO /u01/app/oracle/oradata/dg1/test_undo.dbf 100 NO

添加数据文件
SQL> alter tablespace test_undo_two
2 add datafile '/u01/app/oracle/oradata/dg1/test_undo_add1.dbf'
3 size 100m;

Tablespace altered.
再次查询已经增加完成,
SQL> select tablespace_name,file_name,bytes/(1024*1024) M,autoextensible
2 from dba_data_files
3 where tablespace_name='TEST_UNDO_TWO';

TABLESPACE_NAME FILE_NAME M AUTOEXTENSIBLE
------------------------------ ------------------------------------------------------------ --------------- -----------------------------------
TEST_UNDO_TWO /u01/app/oracle/oradata/dg1/test_undo.dbf 100 NO
TEST_UNDO_TWO /u01/app/oracle/oradata/dg1/test_undo_add1.dbf 100 NO

三、前面TEST_UNDO_TWO表空间的数据文件不能自动拓展,现在将包含的两个数据文件都设置为自动拓展
SQL> alter database
2 datafile '/u01/app/oracle/oradata/dg1/test_undo.dbf','/u01/app/oracle/oradata/dg1/test_undo_add1.dbf'
3 autoextend on;

Database altered.

SQL> select tablespace_name,file_name,bytes/(1024*1024) M,autoextensible
2 from dba_data_files
3 where tablespace_name='TEST_UNDO_TWO';

TABLESPACE_NAME FILE_NAME M AUTOEXTENSIBLE
------------------------------ ------------------------------------------------------------ --------------- -----------------------------------
TEST_UNDO_TWO /u01/app/oracle/oradata/dg1/test_undo.dbf 100 YES
TEST_UNDO_TWO /u01/app/oracle/oradata/dg1/test_undo_add1.dbf 100 YES

切换当前默认UNDO表空间
在实际生产中,如还原表空间的磁盘空间受限,还原表空间所在的磁盘过于繁忙(有其他进程争用),为了减少与其他进程争用带来的高I/O或者避免磁盘空间受限的限制。需要通过切换还原表空间来提高数据库的磁盘性能。在Oracle中一个实例只允许有一个active(活跃)的还原表空间,其他undo表空间全部为inactive(不活跃)的状态,RAC为所有实例的active状态undo表空间全部结合为一个共有还原段使用。
切换默认undo表空间演示
首先查看当前默认undo表空间
SQL> show parameter undo_tablespace;

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_tablespace string UNDO_NUM_ONE

切换为test_undo_two
SQL> alter system set undo_tablespace=test_undo_two;

System altered.
再次查看
SQL> show parameter undo_tablespace;

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_tablespace string TEST_UNDO_TWO

下面详细 解析切换UNDO表空间涉及的过程
1、旧的表空间上还在执行的事务,则旧的表空间状态变成pending offline(等待离线)。
2、用户运行的事务正常运行,切换操作结束,不会等待旧的UNDO表空间的事务结束。
3、切换操作完成后,所有新的事务所产生的undo数据都会存放在新指定的undo表空间中。
4、成为pending offline状态的undo表空间不能被删除
5、旧的undo表空间上的所有事务都提交后,旧的undo表空间状态会由pending offline状态变为offline状态,此时这个undo表空间可以被删除。
6、执行drop tablespace 表空间,相当于 drop tablespace 表空间 including contents (删除所有extent区段,HWM会立即降下)
7、如果undo表空间内包含inactive(不活跃)状态undo数据块,不影响被删除,但此时由于还没有超过undo_retention参数设定的数据保留时间(自动状态下最小值为900秒),此时删除如需要使用当前回滚信息时就会找不到数据而报错。最好等待超过undo_retention参数的保留时间再删除表空间。

四、利用dba_undo_extents数据字典中查找undo段记录的原数据
该数据字典记录所有undo表空间记录undo段的分配信息,包括记录表空间的名字、段、区段、数据文件ID、数据块ID、retention保留状态等信息。

测试
创建T表插入一行数据
create table t (id number,name varchar2(10));
insert into t values (1,'dachen');
查询此条更新记录回滚段的名字
SQL> select a.username,b.name,c.used_ublk from v$session a,v$rollname b,v$transaction c
2 where a.saddr=c.ses_addr and b.usn=c.xidusn;
USERNAME NAME USED_UBLK
------------------- ------------------------------------ -----------------
SCOTT _SYSSMU5_2093046892$ 1

v$session:记录用户关于会话信息
v$rollname:记录回滚段的名字
v$transaction:记录关于事务的信息

通过查询到的回滚段名字,查询该回滚段在所在表空间、区段等信息
SQL> select segment_name,tablespace_name,extent_id from
2 dba_undo_extents
3 where segment_name='_SYSSMU5_2093046892$';

SEGMENT_NAME TABLESPACE_NAME EXTENT_ID
------------------------------ ------------------------------ ---------------
_SYSSMU5_2093046892$ UNDO_TEST_20170908 0
_SYSSMU5_2093046892$ UNDO_TEST_20170908 1

猜你喜欢

转载自blog.csdn.net/qqww120102/article/details/77994066
今日推荐