相克军 ORACLE 讲座 深度剖析UNDO段 笔记.docx
《相克军 ORACLE 讲座 深度剖析UNDO段 笔记.docx》由会员分享,可在线阅读,更多相关《相克军 ORACLE 讲座 深度剖析UNDO段 笔记.docx(19页珍藏版)》请在冰豆网上搜索。
相克军ORACLE讲座深度剖析UNDO段笔记
相克军ORACLE讲座深度剖析UNDO段笔记
UNDO表空间用来存放改变前的旧值。
里面也有段区块,ORACLE自动建立生成、自动使用UNDO段。
作为高级别的DBA是需要知道ORACLE如何使用UNDO段的。
1Undo表空间及管理方式
ORACLE开始一个事务的时候,会用到表空间。
将修改前的数据保存在UNDO段里。
Undo的三个作用
读的一致性,构造CR块
回滚
实例恢复(时的回滚)
--查询UNDO表空间的名字
SQL>showparameterundo_tablespace;
NAMETYPEVALUE
-----------------------------------------------------------------------------
undo_tablespacestringUNDOTBS1
--查询UNDO表空间的数据文件
SQL>selectfile_name,bytes/1024/1024fromdba_data_fileswheretablespace_namelike'%UNDOTBS1%'
FILE_NAME
BYTES/1024/1024
-----------------------------------------------------------------------------------------------
/opt/oracle/oradata/orcl/undotbs01.dbf275
--查询UNDO表空间的段
SQL>select*fromv$rollname;
USNNAME
----------------------------------------
0SYSTEM
1_SYSSMU1$
.........
10_SYSSMU10$
--查询其中='_SYSSMU1$'这个段的占有多个块多少个区
SQL>selectsegment_name,blocks,extentsfromdba_segmentswheresegment_name='_SYSSMU1$';
SEGMENT_NAMEBLOCKSEXTENTS
----------------------------------------------------------------------------------------------------
_SYSSMU1$193617
--查询'_SYSSMU1$'这个段分配区的具体情
SQL>selectsegment_name,tablespace_name,extent_id,file_id,block_id,blocksfromdba_extentswheresegment_name='_SYSSMU1$';
SEGMENT_NAMETABLESPACE_NAMEEXTENT_IDFILE_IDBLOCK_IDBLOCKS
------------------------------------------------------------------------------------------------------------------------------------------------------
_SYSSMU1$UNDOTBS10298
_SYSSMU1$UNDOTBS11288498
.........................................
_SYSSMU1$UNDOTBS1162905128
由上面这个结果,可以得出结果:
UNDO表空间中的段中的区中的块儿是连续的,但是区与区之不是连续的
showparameterundo;
NAMETYPEVALUE
-----------------------------------------------------------------------------
undo_managementstringAUTO
undo_retentioninteger900
undo_tablespacestringUNDOTBS1
showparameterundo;
NAMETYPEVALUE
-----------------------------------------------------------------------------
undo_managementstringAUTO
undo_retentioninteger900--ORACLE不希望已经提交的事务,对应的UNDO段中的区,立即就被覆盖,而设定这个参数undo_retention900表示事务已经提交之后,UNDO段中的区还可以在UNDO段中存活900秒,过期之后,才可以被覆盖
undo_tablespacestringUNDOTBS1
selectnamefromv$parameterwherenamelike'%undo%';
undo_management
undo_tablespace
undo_retention
altertablespaceundotbs1retentionguarantee;--表示undo_retention至少900秒以后,过期之后,才可以被覆盖
selecttablespace_name,retentionfromdba_tablespaces;--查询设置结果
altertablespaceundotbs1retentionnoguarantee;
selecttablespace_name,retentionfromdba_tablespaces;--查询设置结果
Undo段中区的状态
free空闲
expired过期:
超UNDO段中的区在提交之后,存活的时间超过了undo_retention900钞
inactive已经提交
active活动
ORACLE在自动使用Undo段中区时,先用“free”空间,实在不行,才用“expired”过期的空间。
如果空间还不够,用户“inactive”,如果还是空间不够,这时就要报错了。
进程就要挂起了。
ORACLE使用Undo段空间的顺序:
“free”空间--->“expired”过期的空间---->“inactive”空间---如果空间还不够---->报错
检查UNDOSegment状态
SELECTusn,xacts,rssize/1024/1024/1024,hwmsize/1024/1024/1024,shrinks
fromv$rollstatorderbyrssize;
显示UNDO
selectextent_id,bytes,statusfromdba_undo_extentswheresegment_name='_SYSSMU1$';
检查UNDOSegment状态
selecta.usn,a.xacts,a.rssize/1024/1024/1024,a.hwmsize/1024/1024/1024,a.shrinksfromv$rollstataorderbyrssize;
2、图解一个事务的操作流程
Undo段的组成,段头、回滚块
事务ID
selecta.xid,a.xidusn,a.xidslot,a.xidsqn,a.ubablk,a.ubafilfromv$transactiona;
XIDXIDUSNXIDSLOTXIDSQNUBABLKUBAFIL
------------------------------------------------------------------
090016004B050000922135510332
事务表:
undo段的第一数据块,每一个回滚段最多可以47个事务
回滚段的段头块
select*fromv$rollname;
selectheader_block,header_filefromdba_segmentswheresegment_name='_SYSSMU1$';
--将回滚段“_SYSSMU1$”这个段的段头块给dump文件:
altersystemdumpundoheader'_SYSSMU1$';//转储回滚段头
selectspidfromv$processwhereaddrin(selectpaddrfromv$sessionwheresid=(selectsidfromv$mystatwhererownum=1));
--查看UNDO段段头块的内容dump出来的信息
cd$ORACLE_BASE/admin/$ORACLE_SID/dump/
viorcl_ora_9051.trc
altersystemdumpdatafile5block4038;//转储回滚段数据块
事务槽:
一个事务修改一个数据块,一个数据块可能被多个事务修改。
在这个数据块的头部,有一个事务槽,可以写入1-255个事务。
开始一个事务,找到一个回滚段里找一到一个段,在它的控制槽里写上事务信息
在要修改的数据块的事务槽里写上事务信息。
此少要在两个位置写上事务信息:
1)回滚段的段头块里2)数据块的事务槽里。
UBA:
(undoblock)回滚块
要修改数据时,先将修改前的数据放到UNDO段里,叫回滚块
ORACLE事务处理的五大步骤:
第一件事:
一个事务开始,在UNDO表空间里找一个相对空闲的UNDO段,然后在这个UNDO段的段头块里边的事务表里,找到其中一个槽位,在事务表里的槽位里找一个行,
将自己的事务信息XID写上去。
同时在这个回滚段里给这个事务分配一个UNDO块,并且把这个UNDO块儿的地址写到事务表里去。
即在事务表里要写入两个地址:
xid(事务ID),uba(所分配的UNDO块儿的地址)
第二件事:
在修改数据块之前,首先找到这个要修改的数据块的头部,找到它的事务槽,在事务槽里找一行,把事务编号XID写上。
同时事务槽里与有个uba地址指向回滚块。
第三件事:
把要修改的五行信息写到UNDO块里(回滚块),并且把这个UNDO块儿的地址写到数据块里的事务槽里的uba地址。
第四件事:
接下来,还要修改其它信息,再分一个UNDO块,将新分配的uba地址记录到数据块的事务槽里。
第五件事:
事务表里的uba地址就指向了最新分配的UNDO块。
这样形成了两条链:
第一组链:
由数据块的事务槽的XID指向事务表的事务,同时,数据块的事务槽里的uba地址指向UNDO段里UNDO块的地址
作用:
利用这个链接,可以直接从数据块里找到回滚块,直接构造出CR块。
而不用通过事务表,找到回滚块。
疑问:
为什么事务ID,即XID同时存在两个地方:
事务表和数据块里?
为什么需要数据块儿的SID还要指向事务表里的事务ID。
第二组链:
事务表uba指向最新的回滚块,最新的回滚块能找到次新的回滚块,次新的回滚块能找到更新的回滚块,以此形成一条链。
作用:
事务表里的uba指向最新的回滚快。
使用最新的回滚块找到次新的回滚块,把次新的回滚块回滚了,这样依次往前回滚rollback。
总结:
一个事务开始以后ORACLE修改了1)事务段的段头块的事务表,2)UNDO块,3)数据块的事务槽,4)数据块本身
这四个被修改的地方都在数据块里。
所以全都会产生REDO。
所以REDO不仅仅记录数据的改变,而且记录了1)事务表的改变2)UNDO块的改变3)数据块事务槽的改变4)数据块的改变
5、读一致性
ORA-01555错误
6、undoadvisor
EM
7、事务槽ITL
默认是1
最大255(从ORACLE10G开始不能更改)
selectINI_TRANS,MAX_TRANSfromdba_tableswheretable_name='T2';
事务槽的争用
事务槽的争用:
如上图,当未提交的事务不断增多,而多A事务和B事务都同时在修改这同一个数据块,而且都没有提交,没有提交的事务,事务槽信息是不可以被告覆盖的,必须保留,随着事务的增多,在这个数据块的事务槽里的事务信息会不断的增多,当又有新的事务需要写进这个数据块的事务增时,已经没有空间了,那就这个新的事务就需要等待别的事务提交,只有别的事务提交之后,这个新事务才可以写进去。
这就叫“事务槽的争用”。
如何防止事务槽争用:
1)对于往一个表中多个事务同时插入数据,INSERT操作时,ORACLE给每个事务开启一个数据块。
这样就不会产生事务槽争用。
2)但对于UPDATE和DELETE操作是没有办法解的,所以UPDATE和DELETE操作容易发生事务槽争用。
事务等待及行级锁的形成:
createtablet10(idnumber(5),namechar(2000));
insertintot10values(1,'aa');
insertintot10values(2,'bb');
insertintot10values(3,'cc');
insertintot10values(4,'dd');
insertintot10values(5,'ee');
commit;
selectdbms_rowid.rowid_relative_fno(rowid)fno,dbms_rowid.rowid_block_number(rowid)block_number,id,namefromt10;
updatet10setname='abcd'whereid=1;
在DBA用户下:
selecta.ubafil,a.ubablk,a.xidusn,a.xidsqn,a.start_scnbfromv$transactiona;
selecta.ubafil,a.ubablk,a.xidusn,a.XIDSLOT,a.xidsqn,a.start_scnbfromv$transactiona;
select*fromv$rollname;
将回滚段_syssmu2$的段头块dump成文本,放在$ORACLE_BASE/admin/$ORACLE_SID/dump/目录下,
altersystemdumpundoheader'_SYSSMU2$';
altersystemdumpdatafile2block3657;
查询DUMP出来的文件,查当前会话编号
selectspidfromv$processwhereaddrin(selectpaddrfromv$sessionwheresid=(selectsidfromv$mystatwhererownum;
SPID
------------
9614
cd$ORACLE_BASE/admin/$ORACLE_SID/dump/
事务槽dump文件的内容:
还可以指文件号和块号DUMP出来:
selectdbms_rowid.rowid_relative_fno(rowid)fno,dbms_rowid.rowid_block_number(rowid)block_number,id,namefromt10;
altersystemdumpdatafile4block421;
altersystemdumpdatafile4block422;
8、提交方式
事务的提交:
如果一个事务修改了1000个块,现在这个事务要提交,那么需要修改1001个块中的“是否已提交信息”,1000个数据块+1个事务表。
这时,有可能这1000个块儿已经有800写进了磁盘下了,那么需不需要把这800个块儿重新写到磁盘,再提交,如果这样,会不会很慢?
?
答:
ORACLE针对这个问题,采了快速提交的办法,即当ORACLE发些这次事务修改的数据块过多,提交时,只会更新UNDO表空间里的事务表的“是否提交”
信息给更新了,而数据块事务槽的“是否已经提交”不作更新,或者更新少量。
所以数据块事务槽的“是否已经提交”信息,不一定准确,但是事务表里的“是否已提交”信息一定是准确的。
疑问解答:
为什么事务ID,即XID同时存在两个地方:
事务表和数据块里?
为什么需要数据块儿的SID还要指向事务表里的事务ID。
答:
如图所示,当另一个事务B需要对修改或查询同一个数据块的某一行时,而这一行已经被A事务修改,但是还没有提交。
些时ORACLE会走以下的程序流程:
从这里可以看出几个结论:
1)数据块的XID指向事务表是非常有用的。
2)ORACLE执行SELECT语句,也可能因为更改前面事务留在数据块事务槽里的“是否已提交”状态,而产了logbuffer,
进而生成redolog日志。
3)数据行上的ITL(事务槽的编号)指向事务槽,事务槽上有是琐已提交标识,这种机制实际上形成了ORACLE的行级锁。
4)对ORACLE最彻底的提交方式,是事务表里为“已提交”状态,数据块的事务槽为“已提交”状态,数据行的ITL被清除干净。
但实际上,数据行的ITL事务槽号没有清掉,留待下次查询时,再作清理,并且如果上一个事务较大时,数据块事务槽
里“是否已提交”标识不一定准确,但是事务表里的“是否已提交”信息一定是准确的。
ORACLE执行SELECT语句时,是很有可能产生REDOLOG日志的。
select读的过程分析如下:
ORACLE要读一个表,这个表有10000行,A事务8:
50开始读,8:
55时,另一个B事务删除了一行,并且提交了,9:
00时A事务读表有结果了,
请问ORACLE读到的是9999行,还是10000行?
答:
读到的是10000行,ORACLE是如何实现的呢?
ORACLE在时间8:
50时读这个表的时候,把时间点记下来,生成一个SCN(850),此时此刻,所有的
数据块的事务槽里的SCN都是<=850的。
1)在事务中,对四个地方的修改(数据行、事务槽、事务表、回滚块)全部产生的REDOLOG
2)对数据块的所有修改全部产生RODOLOG
一个数据块可以依据UNDO块数据一直往历史方向找出任意时间的数据块。
如图所示,
只要UNDO表空间足够大,那么可以利用回滚块和当前数据块,不断的构造出CR数据块,以些不断往历史方向构造。
ORACLE的ORA-01555错误
4、图解Oracleprivateredostrands机制
查看回滚段的使用情况,哪个用户正在使用回滚段的资源
select*fromv$transactiont,v$rollstatr,
v$rollnameu,v$sessions
wheres.taddr=t.addrandt.xidusn=r.usnandr.usn=u.usn
orderbys.username;
检查UNDOSegment状态
selectusn,xacts,rssize/1024/1024/1024,
hwmsize/1024/1024/1024,shrinks
fromv$rollstatorderbyrssize;
确定当前例程正在使用的UNDO表空间:
showparameterundo_tablespace;
select*fromv$parameterwherenamelike'%undo%';
显示数据库的所有UNDO表空间
select*fromdba_tablespaceswherecontents='UNDO';
显示UNDO表空间统计信息
selectto_char(begin_time,'HH24:
MI:
SS')BIGIN_TIME,
TO_CHAR(end_time,'HH24:
MI:
SS')END_TIME,undoblks
fromv$undostatA;
显示UNDO段统计信息
selecta.name,b.XACTS,b.WRITES,b.EXTENTSfromv$rollnamea,v$rollstatb
wherea.usn=b.usn;
显示活动事务信息
selecta.username,b.name,used_ublk
fromv$sessiona,v$rollnameb,v$transactionc
wherea.saddr=c.SES_ADDRandb.usn=c.XIDUSN
anda.username='HR';
UNDO表空间大小确定
selecttotalundo/((end-begin)*1440*60)undo_zize_per_secfrom
(selectmax(end_time)end,min(begin_time)begin,sum(undoblks)*8192totalundo
fromv$undostat
);
select140.741516648953*60/1024fromdual;
UNDO与REDO的关系:
他们没有什么关联
执行下面SQL语句,ORACLE的处理全过程:
updatet1setc1='A'WHEREC1='B'
1)找到包含C1='B'的数据据,假设是【4,120】
2)找到一个可用的UNDOBLOCK,假设是【2,300】
3)产生一个redo,去描述(保护)针对UNDOBLOCK的写入操作。
redo_addrSCNfile#block#operation
1009:
003400insert'B'
4)把'B'放入UNDOBLOCK.
5)产生一个REDO,去描述(保护)针对UNDOBLOCK的写入操作。
redo_addrSCNfile#block#operation
1009:
003400'B'-->'A’
6)把‘A’写入[4,120].
以后一担rollback,oracle可以直接把UNDO里的数据重新覆盖过来
ORACLE不提供脏读:
(我的修改,当我没有提交时,别人是读不到的)
比如:
A用户在9:
00执行一个查询SQL,这个表有10000条记录,这个SQL需要执行10分钟才能完成,
但是在9:
09时,B用户把这个表