分享更有价值
被信任是一种快乐

如何进行ITL与事务处理

文章页正文上

如何进行ITL与事务处理,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
一、ITL与事务的关系 ITLinterested transaction list)事务槽是Oracle数据块内部的一个组成部分,位于数据块头(block header)。ITLxidubaflaglckSCN/fsc组成,用来记录在该数据块上所有发生的事务。一个ITL槽位可以看作是一条事务记录,它是Oracle中事务处理的关键组件,如果事务已经提交,则该ITL槽位就可以被反复使用,如果一直不提交,则该ITL槽位一直被占用,里面记录着事务信息、回滚段入口、事务类型等。事务提交后,ITL槽位中仍保存着该事务提交时的SCN号。ITL最小值为1,由参数initrans控制(由于兼容性的原因,Oracle会在对象的存储块上分配两个ITL,因此inittrans的最小值实际上为2),这也是在建表时如果不指定initrans参数时的默认取值,最大值为255,由参数maxtrans控制,最大值参数在Oracle
10g
以后不能被修改。一个ITL占用块46B的空间,当块中还有一定的free space时,Oracle可以使用free space构建ITL供事务使用,如果没有了free
space
,则块因为不能分配新的ITL就可能发生ITL等待。当用户发出一条SQL语句时,Oracle会记录下这个时刻的SCN,然后在buffer cache中查找需要的block,或者从磁盘上读取,当别的会话修改了数据,或者正在修改数据,就会在相应的block上记录ITL,此时Oracle发现ITL中记录的SCN大于select时刻的SCN,那么Oracle就会根据ITL中记录的uba找到undo信息,获得该block的前镜像,然后在buffer
cache
中构造CRconsistent read )块,此时Oracle也会检查构造出来的blockITL记录的SCN,如果SCN仍然大于select时刻的SCN,那么将继续重复构造前镜像,直到前镜像blockITL记录的SCN小于select时刻的SCN,同时检查该事务是否提交或回滚,如果没有,还要继续构造前镜像,直到找到需要的block。如果在构造前镜像过程中所需的undo信息被覆盖了,就会报快照过旧的错误。于是Oracle实现了多版本控制,这就是Oracle多版本的本质,这也就是为什么发出一条select语句时总是会看到consistent gets了。
二、ITL等待 发生ITL等待的场景有以下两种情况:1、超过了maxtrans配置的最大ITL数;2initrans配置不足,且没有足够的free space开扩展ITL
解决办法: maxtrans不足:高并发引起,同一数据块上的事务量已经超出了允许的ITL数量。因此需要减少事务的并发量,对于长事务,在保证数据完整性的前提下,增加commit的频率,将长事务变为短事务,以减少资源占用。initrans不足:数据块上的ITL数量并没有达到maxtrans的限制,发生这种情况的表通常是被较多的update,造成预留空间pctfree(默认10%)被填满。此时可增加表的initranspctfree来解决,如果该表上事务的并发量高,可优先增加initrans,增大ITL槽位的初始分配量,反之,则优先增加pctfree,提升ITL槽位的扩展能力。注意:如果是通过alter table方式修改了表的这两个参数,那么只会影响新的数据块,而不会改变已有数据的数据块。
三、实验验证ITL与事务的关系 连接到scott用户
sqlplus scott/tiger 创建测试表,pctfree设为0
create table t1(a number,
b varchar2(30)) pctfree 0;
begin
for i in 1 .. 1000 loop
insert into t1 values (i, ‘data’);
end loop;
commit;
end;
/
查看段的区间分配信息
col segment_name for a20
col tablespace_name for
a20
select segment_name,
segment_type, tablespace_name, extent_id, file_id, block_id, blocks, bytes from
dba_extents w免费主机域名here owner = ‘SCOTT’ and segment_name = ‘T1’;
SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID
BLOCK_ID BLOCKS BYTES
——————–
—————— ——————– ———- ———- ———-
———- ———-
T1 TABLE USERS 0 4 168 8
65536
查看块分配信息
select
distinct dbms_rowid.rowid_block_number(rowid) from scott.t1;
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
————————————
171
174 由此可知,t1表的数据占用了两个数据块,块编号分别为171174t1段的第一个区间的起始编号为168,该区间由8个数据块组成。下面在同一个数据块171上同时执行多个事务,看看到底会发生什么。session1
update
scott.t1 set b = ‘Oracle data’ where a

已更新10行。 session2
update
scott.t1 set b = ‘Oracle data’ where a > 10 and a

已更新10行。 session3先确定当前会话的sidselect
sid from v$mystat
where rownum = 1;
SID
———-
136
update
scott.t1 set b = ‘Oracle data’ where a > 20 and a
操作被hang住,事务处于等待状态。
查看会话的等待事件
col event for a30 select
sid,
event, seconds_in_wait, state from v$session_wait where sid = 136;
SID EVENT SECONDS_IN_WAIT STATE
———-
—————————— ————— ——————-
136 enq: TX – allocate ITL entry 242 WAITING 此时出现了分配ITL条目的等待。因为默认的初始ITL槽位分配为2,而pctfree0,两个事务不提交,block中就没有足够空间分配ITL了,因此出现了会话被hang住一直在等待ITL的分配。前面的会话提交或回滚后,后面的会话才得以执行。
四、ITL进一步研究 当一个事务完成时,Oracle需要执行块清理(block
cleanout
),清理掉这些在数据块上的事务数据,清除ITL中的标志位、行中row header中的标志位等。块清理分为两种:fast commit block cleanoutdeferred block cleanout快速提交块清理(fast commit block cleanout):这是Oracle的默认行为。延迟块清理(deferred block cleanout):事务提交时,Oracle仅简单的更新相关回滚段的头部信息,而把数据块的清理操作留给后来需要读写这个数据块的操作者(之后的事务)。设想一个update大量数据的操作,因为执行时间较长,一部分已修改的块已被缓冲池flush out写至磁盘,当update操作完成执行commit操作时,为进行块清理,需要将那些已经写至磁盘的数据块重新读入,这将消耗大量I/O,并使commit操作十分缓慢。为解决这个问题,Oracle使用了延迟块清理的方案,对待存在以下情况的块,commit操作不做块清理:1、在更新过程中,被缓冲池flush out写至磁盘的块;2、当更新操作涉及的块超过了块缓冲区缓存的10%时,超出部分的块。虽然commit放弃对这些块的清理,但仍会修改回滚段的段头,回滚段的段头包括了段中的事务信息,commit操作将本事务转化为非active状态。当下一次操作如selectupdateinsertdelete访问到这些块时再来完成对块的清理,这称之为延迟块清理。块延迟清除通过事务槽上的回滚段号、槽号等信息访问回滚段头的事务信息,若事务不再活跃或事务过期则完成块清理。块延迟清除的影响在select操作过程中体现的最为明显,这也是select语句产生redo信息的主要原因。继续前面的案例,先执行一个更新启动一个新的事务,然后查询出此更新涉及的数据块,然后dump该数据块的内容,进一步验证ITL的信息。
执行更新
update
scott.t1 set b = ‘Oracle data’ where a = 100;
确定更新所在的文件号和块号
select
dbms_rowid.rowid_relative_fno(rowid) from scott.t1 where a = 100;
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)
————————————
4
select
dbms_rowid.rowid_block_number(rowid) from scott.t1 where a = 100;
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
————————————
171
开启会话跟踪
alter session
set sql_trace=true;
oradebug
setmypid
oradebug
tracefile_name
c:oraclediagrdbmsmesmestracemes_ora_3852.trc dump数据块
alter system
dump datafile 4 block 171; 查看跟踪文件c:oraclediagrdbmsmesmestracemes_ora_3852.trc,可以看到关于ITL的信息:
Block header dump: 0x010000ab
Object id on Block? Y
seg/obj: 0x12458 csc: 0x00.1eb08d itc: 2
flg: E typ: 1 – DATA
brn: 0
bdba: 0x10000a8 ver: 0x01 opc: 0
inc: 0
exflg: 0
Itl
Xid Uba Flag
Lck Scn/Fsc
0x01 0x0007.015.0000040c 0x00c00618.017a.07 C-U-
0 scn 0x0000.001ea944
0x02 0x0006.00e.000004ee 0x00c011d1.014e.1e —-
1 fsc 0x0002.00000000 flag:事务状态标志,占用块中的一个字节,对应于v$transaction视图中的status字段,意义如下:—-transaction is active or committed pending
cleanout
c—transaction has been committed and locks
cleaned out
–u-transaction committedmaybe long ago),SCN is an upper bound-b–this undo record contains the undo for this
ITL entry
—ttransaction was still active at block
cleanout SCN
SCN/fsc:该ITL对应的事务提交时的SCN,那么这里所有槽位上最大的一个SCN号就表示这个block最后被更新时的SCN。每一个事务对应一个ITL记录,如果该事务没有涉及延迟块清理,那么显示的是fsc,如果是延迟块清理,那么显示的就是SCNlck:事务锁影响的记录数。对照视图v$transaction,获取此处update操作对应的事务信息
select xidusn, xidslot,
xidsqn, ubafil, ubablk, ubasqn, ubarec from v$transaction;
XIDUSN
XIDSLOT XIDSQN UBAFIL
UBABLK UBASQN UBAREC
———- ———-
———- ———- ———- ———- ———-
6 14 1262 3 4561 334 30 xid:其构成是xidusn.xidslot.xidsqn,三部分信息分别表示xidusnundo segment number 回滚段号xidslotslot number 事务槽号xidsqnsequence number 序列号uba:其构成是dba.ubasqn.ubarec,而dba包含了ubafilubablk的信息,分解如下select
dbms_utility.data_block_address_file(to_number(‘
00c011d1‘, ‘xxxxxxxx’)) ubafil,
dbms_utility.data_block_address_block(to_number(‘
00c011d1‘, ‘xxxxxxxx’)) ubablk from dual;
UBAFIL
UBABLK
———- ———-
3
4561 ubafilundo block addressuba filenum 回滚块地址文件号ubablkundo block number 回滚块地址块号ubasqnuba sequence number 回滚块地址序列号ubarecuba record number 回滚块地址记录号于是根据uba信息,可以从回滚段的数据块中找到该项事务的回滚信息,为此可以dump回滚段的数据块
alter system
dump datafile 3 block 4561;
查看跟踪文件信息,找到该事务对应的回滚信息
UNDO BLK:
xid:
0x0006.00e.000004ee seq: 0x14e cnt:
0x1e irb: 0x1e icl: 0x0
flg: 0x0000 这里的seq即序列号ubasqncnt即记录号ubarec。由rec #0x1e可以进一步在trace文件中找到update前的回滚信息
* Rec #0x1e slt: 0x0e
objn: 74840(0x00012458) objd:
74840 tblspc: 4(0x00000004)
* Layer:
11 (Row) opc: 1 rci 0x1d
Undo type: Regular undo
Last buffer split: No
Temp Object: No
Tablespace Undo: No
rdba: 0x00000000
*—————————–
KDO undo record:
KTB Redo
op: 0x02 ver: 0x01
compat bit: 4 (post-11)
padding: 0
op: C uba: 0x00c011d1.014e.1c
KDO Op code: ORP row
dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x010000ab hdba: 0x010000aa
itli: 2 ispac: 0
maxfr: 4858
tabn: 0 slot: 99(0x63)
size/delt: 11
fb: –H-FL– lb: 0x2 cc: 2
null: —
col 0: [ 2]
c2 02
col 1: [ 4]
64 61 74 61 fb:行标记,H表示head of rowFL分别表示行的first piecelast
piece
,说明此行涉及导出的数据块,不存在行链接,又由于块中存在行头,说明也存在行迁移。lbITL事务槽编号cc:列的数量回滚前的编码是64 61 74 61,转换为原始字符信息
select
chr(to_number(64, ‘xx’)) || chr(to_number(61, ‘xx’)) || chr(to_number(74,
‘xx’)) || chr(to_number(61, ‘xx’)) undo_data from dual;
UNDO_DAT
——–
data 以上测试可见,Oracle是通过数据块中的ITL信息来找到事务对应的回滚信息,同时实现了事务的读一致性。如果事务已完成,ITL就可以被重用。
五、ITL与CR块 Oracle的锁管理是一种轻量级的锁定机制,不是通过构建锁列表来进行数据锁定管理的,而是直接将锁作为数据块的属性存储在数据块头部,通过ITL实现。一个事务要修改块中的数据,必须获得改块中的一个ITL(通过initrans预先分配的或者是通过pctfree space后来构建的),通过ITLundo segment header中的transaction table,可以知道事务处于活动阶段还是已经完成。事务在修改块时会检查row header中的标志位,如果该标志位为0(该行没有被活动的事务锁住,这是可能要进行延迟块清除等工作),就把该标志位修改为事务在该块获得的ITL序号,这样当前事务就获得了对记录的锁定,然后就可以修改行数据了。与此同时,在该事务处理过程中,如果有会话查询该数据块中的数据,Oracle就会读取回滚段中的内容来构造保障数据读一致性的CRconsistent read)块。在多用户并发环境下,一个数据块可以有多个CR版本,Oracle会在下列情况下构造数据块的CR版本:1、如果一个数据块上有锁,而有会话需要读取这个数据块中的内容,Oracle就会构造该数据块的CR版本;2、是否需要构造CR块,与SCN密切相关。如果一个查询游标对应的SCN小于数据块当前的SCN,此时Oracle需要构造对应查询游标SCNCR块。
以下看一下数据块及其不同版本的例子,操作分别在几个不同会话中进行。 session1
查出表中数据所在的文件号和块号
select distinct
dbms_rowid.rowid_relative_fno(rowid) file#,
dbms_rowid.rowid_block_numb免费主机域名er(rowid) block# from scott.emp;
FILE#
BLOCK#
———- ———- 4 151
由文件号和块号查询缓存中的数据块,此时还没有该数据块信息 select
file#, block#, status, dirty, objd, ts# from v$bh where file#
= 4 and block# = 151;
未选定行
对数据做查询操作
select * from
scott.emp; 缓存中产生了数据块的xcur版本select
file#, block#, status, dirty, objd, ts# from v$bh where file#
= 4 and block# = 151;
FILE#
BLOCK# STATUS D OBJD TS#
———- ———-
———- – ———- ———-
4 151 xcur N
73196 4
刷新缓存
alter system
flush buffer_cache; 缓存中的数据块没有消失,但状态变为了free版本select
file#, block#, status, dirty, objd, ts# from v$bh where file#
= 4 and block# = 151;
FILE#
BLOCK# STATUS D OBJD TS#
———- ———-
———- – ———- ———-
4 151 free N
73196 4
对数据再次做查询操作
select * from
scott.emp; 查询缓存块,此时多了一个xcur版本
select file#, block#,
status, dirty, objd, ts# from v$bh where file#=4 and block#=151;
FILE#
BLOCK# STATUS D OBJD TS#
———- ———-
———- – ———- ———-
4 151 free N
73196 4
4 151 xcur N
73196 4 session2
对数据块进行更新操作,但不提交
update
scott.emp set sal = 1000 where empno =7369; session1查询缓存块,dirty列标志为Y,表示为脏数据
select file#, block#,
status, dirty, objd, ts# from v$bh where file#=4 and block#=151;
FILE#
BLOCK# STATUS D OBJD TS#
———- ———-
———- – ———- ———-
4 151 free N
73196 4
4 151 xcur Y
73196 4
再次对数据做查询操作
select * from
scott.emp; 查询缓存块,又多了一个cr版本,因为之前session2的更新没有提交,所以session1查询时,通过读取回滚段在buffer cache中构建了CR块。
select file#, block#,
status, dirty, objd, ts# from v$bh where file#=4 and block#=151;
FILE#
BLOCK# STATUS D OBJD TS#
———- ———-
———- – ———- ———-
4 151 free N
73196 4
4 151 xcur Y
73196 4
4 151 cr N
73196 4 session2
提交更新
commit; session1
再次对数据做查询操作
select * from
scott.emp;
查询缓存块,状态信息不变,因为是否提交并不影响数据块内容
select file#, block#,
status, dirty, objd, ts# from v$bh where file#=4 and block#=151;
FILE#
BLOCK# STATUS D OBJD TS#
———- ———-
———- – ———- ———-
4 151 free N
73196 4
4 151 xcur Y
73196 4
4 151 cr N
73196 4 session2
再次更新数据,但不提交
update scott.emp set sal
= 800 where empno =7369; session1
对数据做查询操作
select * from
scott.emp; 查询缓存块,可以看到又新构建了一个CR版本
select file#, block#,
status, dirty, objd, ts# from v$bh where file#=4 and block#=151;
FILE#
BLOCK# STATUS D OBJD TS#
———- ———-
———- – ———- ———-
4 151 free N
73196 4
4 151 xcur Y
73196 4
4 151 cr N
73196 4
4 151 cr N
73196 4 session2
提交更新
commit; session1
对数据做查询操作
select * from
scott.emp;
查询缓存块,状态不改变
select file#, block#,
status, dirty, objd, ts# from v$bh where file#=4 and block#=151;
FILE#
BLOCK# STATUS D OBJD TS#
———- ———-
———- – ———- ———-
4 151 free N
73196 4
4 151 xcur Y
73196 4
4 151 cr N
73196 4
4 151 cr N
73196 4
数据块在缓存中的状态及其物理意义如下: freenot currently in usexcurexclusivescurshared currentcrconsistent readreadbegin read from diskmrecin media recovery modeirecin instance recovery mode关于如何进行ITL与事务处理问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注云技术行业资讯频道了解更多相关知识。

相关推荐: PostgreSQL的相似搜索插件有哪些

这篇文章主要介绍“PostgreSQL的相似搜索插件有哪些”,在日常操作中,相信很多人在PostgreSQL的相似搜索插件有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL的相似搜索插件有哪些”的疑惑有所帮…

文章页内容下
赞(0) 打赏
版权声明:本站采用知识共享、学习交流,不允许用于商业用途;文章由发布者自行承担一切责任,与本站无关。
文章页正文下
文章页评论上

云服务器、web空间可免费试用

宝塔面板主机、支持php,mysql等,SSL部署;安全高速企业专供99.999%稳定,另有高防主机、不限制内容等类型,具体可咨询QQ:360163164,Tel同微信:18905205712

主机选购导航云服务器试用

登录

找回密码

注册