ITL的含义
ITL,即Interested Transaction List,也就是事务槽,是一种数据块的内部结构,它位于数据块头中。当对数据块做修改的时候,进程需要获取一个空的事务槽。ITL事物槽由槽位号、XID、Uba、Flag、Lck、Scn/Fsc组成。ITL的个数是由参数initrans控制,maxtrans参数已经被废弃。默认initrans值是1,但是实际上此时ITL槽个数是2.当大量并发的update语句发生时,可能会因为槽位不够分配而出现等待事件enq: TX - allocate ITL entry。
可能会有人疑问,默认是2个槽位的话,对oltp的系统而言岂不是很容易就发生这个等待事件,其实不是这样的。ITL槽也是需要空间的,这2个只是预分配,只要数据块还有空间,就可以再次分配,直到数据块上没有空间分配了。而且ITL槽是可循环使用的,只要事物提交了就可以再次重用。说到这里就想到了pctfree参数了,默认是10%空余空间,这部分空间是可以用来分配事务槽的。
模拟enq: TX – allocate ITL entry等待
创建测试表: SQL> create table test (a number,b varchar2(2000)) initrans 1 pctfree 0; Table created.
插入数据: SQL> insert into test select object_id,lpad(object_name,2000,'x') from dba_objects where rownum<50; SQL> commit; Commit complete. SQL> select distinct dbms_rowid.rowid_relative_fno(rowid) file#, 2 dbms_rowid.rowid_block_number(rowid) block# from test ;
FILE# BLOCK# ---------- ---------- 7 1295 7 1289 12 2411 7 1291 12 2422 12 2414 7 1294 12 2413 12 2412 12 2415 7 1292
FILE# BLOCK# ---------- ---------- 7 1288 7 1290 7 1293
14 rows selected.
[oracle@oggtest1 ~]$ more bbed.par blocksize=8192 listfile=/home/oracle/filelist.txt mode=edit [oracle@oggtest1 ~]$ more filelist.txt 7 /tpdata/oradata/ogg1/test01.dbf 12 /tpdata/oradata/ogg1/test02.dbf
BBED> set file 7 block 1290 FILE# 7 BLOCK# 1290
BBED> map File: /tpdata/oradata/ogg1/test01.dbf (7) Block: 1290 Dba:0x01c0050a ------------------------------------------------------------ KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes @0
struct ktbbh, 72 bytes @20
struct kdbh, 14 bytes @100
struct kdbt[1], 4 bytes @114
sb2 kdbr[4] @118
ub1 freespace[26] @126
ub1 rowdata[8036] @152
ub4 tailchk @8188
BBED> p ktbbh struct ktbbh, 72 bytes @20 ub1 ktbbhtyp @20 0x01 (KDDBTDATA) union ktbbhsid, 4 bytes @24 ub4 ktbbhsg1 @24 0x000130e7 ub4 ktbbhod1 @24 0x000130e7 struct ktbbhcsc, 8 bytes @28 ub4 kscnbas @28 0x009eeb6f ub2 kscnwrp @32 0x0000 sb2 ktbbhict @36 7938 ub1 ktbbhflg @38 0x32 (NONE) ub1 ktbbhfsl @39 0x01 ub4 ktbbhfnx @40 0x03000968 struct ktbbhitl[0], 24 bytes @44 struct ktbitxid, 8 bytes @44 ub2 kxidusn @44 0x0003 ub2 kxidslt @46 0x0004 ub4 kxidsqn @48 0x00005560 struct ktbituba, 8 bytes @52 ub4 kubadba @52 0x00c00695 ub2 kubaseq @56 0x0370 ub1 kubarec @58 0x12 ub2 ktbitflg @60 0x2004 (KTBFUPB) union _ktbitun, 2 bytes @62 sb2 _ktbitfsc @62 0 ub2 _ktbitwrp @62 0x0000 ub4 ktbitbas @64 0x009eeb73 struct ktbbhitl[1], 24 bytes @68 struct ktbitxid, 8 bytes @68 ub2 kxidusn @68 0x0000 ub2 kxidslt @70 0x0000 ub4 kxidsqn @72 0x00000000 struct ktbituba, 8 bytes @76 ub4 kubadba @76 0x00000000 ub2 kubaseq @80 0x0000 ub1 kubarec @82 0x00 ub2 ktbitflg @84 0x0000 (NONE) union _ktbitun, 2 bytes @86 sb2 _ktbitfsc @86 0 ub2 _ktbitwrp @86 0x0000 ub4 ktbitbas @88 0x00000000 ub1 freespace[26] :表明这个块上还剩下26bytes struct ktbbhitl[0], 24 bytes和struct ktbbhitl[1], 24 bytes代表两个itl槽,因为创建表时指定initrans为1,一个itl槽大小为24bytes。 所以,这个数据块上最多只能承受三个事物,2个事物可以用现成的itl槽,还可以从块的空闲空间中分配第三个槽位,但是分配完之后块只剩2bytes,不够分配第四个槽位,所以当第四个事物来临时,就会发生enq: TX - allocate ITL entry等待事件。 SQL> select a 2 from (select a, dbms_rowid.rowid_block_number(rowid) block# from test) 3 where block# = 1290 and rownum<=5;
A ---------- 52 30 18 50
session1: update test set b=b where a=52; session2: update test set b=b where a=30; session3: update test set b=b where a=18; session4: update test set b=b where a=50;
此时出现enq: TX - allocate ITL entry等待事件: \n=============Wed Jun 27 04:42:49 CST 2018===================\n
INST_ID EVENT# EVENT COUNT(*) ---------- ---------- ------------------------------- ---------- 1 341 SQL*Net message to client 1 1 238 enq: TX - allocate ITL entry 1 此时将第一个事物提交,第四个事物修改成功: SQL> update test set b=b where a=50;
1 row updated. Itl槽被重用了。 等待事件也消失了: \n=============Wed Jun 27 05:02:01 CST 2018===================\n
INST_ID EVENT# EVENT COUNT(*) ---------- ---------- ------------------------------- ---------- 1 341 SQL*Net message to client 1
|
数据块dump文件解读
Dump出file 7 block 1290数据块:
SQL> oradebug setmypid Statement processed. SQL> alter system dump datafile 7 block 1290;
System altered.
SQL> oradebug tracefile_name /tpsys/app/oracle/diag/rdbms/ogg1/ogg1/trace/ogg1_ora_22110.trc |
Start dump data blocks tsn: 8 file#:7 minblk 1290 maxblk 1290
Block dump from cache:
Dump of buffer cache at level 4 for tsn=8, rdba=29361418
BH (0x8df761c8) file#: 7 rdba: 0x01c0050a (7/1290) class: 1 ba: 0x8d1b4000
set: 3 pool 3 bsz: 8192 bsi: 0 sflg: 2 pwc: 1121,28
dbwrid: 0 obj: 78055 objn: 78055 tsn: 8 afn: 7 hint: f
hash: [0x85f66918,0xa7f5f768] lru: [0x85f66950,0x8dfb3b20]
ckptq: [NULL] fileq: [NULL] objq: [NULL]
st: CR md: NULL tch: 1
cr: [scn: 0x0.9eee55],[xid: 0x9.1e.556e],[uba: 0xc08d9d.392.b],[cls: 0x0.9eee55],[sfl: 0x1],[lc: 0x0.9eee55]
flags: only_sequential_access
cr pin refcnt: 0 sh pin refcnt: 0
tsn:tablespace number,tsn:8代表表空间号为8的表空间。 SQL> select ts#,NAME from v$tablespace where ts#=8;
TS# NAME ---------- ------------------------------ 8 TEST
File#:7是指文件号为7的数据文件: SQL> select file_id,FILE_NAME,TABLESPACE_NAME from dba_data_files where file_id=7; FILE_ID FILE_NAME TABLESPACE_NAME ---------- -------------------------------------------------- ------------ 7 /tpdata/oradata/ogg1/test01.dbf TEST minblk 1290 maxblk 1290是指dump的数据块的范围。
rdba=29361418和rdba: 0x01c0050a (7/1290): rdba就是相对数据块的位置,一个是10进制,一个是16进制。含义是7号数据文件的1290号块。 SQL> select to_number('1c0050a','xxxxxxxxxxxxxxxxxx') from dual;
TO_NUMBER('1C0050A','XXXXXXXXXXXXXXXXXX') ----------------------------------------- 29361418 class: 1:表示块的类型。1代表数据块。对应x$bh.class。 ba: 0x8d1b4000:block address。指块在buffer cache中的内存地址,即x$bh.ba
set: 3即x$bh.state,3代表一致性读。 bsz: 8192,block size 8k。 dbwrid: 0 obj: 78055 objn: 78055 tsn: 8 afn: 7 dbwn的n是0。Obj是x$bh.obj,是指数据所在对象的id。Objn:object name id。 tsn上面有,afn,绝对数据文件号。
hash: [0x85f66918,0xa7f5f768] 哈希链表后面和前面的位置。哈希链表是双向的,即x$bh.nxt_hash x$bh.prv_hash
lru: [0x85f66950,0x8dfb3b20] lru链表后面和前面的位置。这条链也是双向的,即x$bh.nxt_repl x$bh.prv_repl
st: CR一致性读。 tch: 1。访问次数为1 ckptq: [NULL] 检查点队列哈希值
fileq: [NULL] 文件队列哈希值
cr: [scn: 0x0.9eee55],[xid: 0x9.1e.556e],[uba: 0xc08d9d.392.b],[cls: 0x0.9eee55],[sfl: 0x1],[lc: 0x0.9eee55] 产生此cr块时的scn。 Xid事务id,因为此事务产生了一致性读。 Uba:回滚段地址。undo文件号和数据块号+回滚序列号+回滚记录号 。
flags: only_sequential_access。对应x$bh. FLAG |
Block header dump: 0x01c0050a
Object id on Block? Y
seg/obj: 0x130e7 csc: 0x00.9f5691 itc: 3 flg: E typ: 1 - DATA
brn: 1 bdba: 0x3000968 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0009.01e.0000556e 0x00c08d9d.0392.0b ---- 1 fsc 0x0000.00000000
0x02 0x0007.013.000054a6 0x00c0093c.02d6.08 ---- 1 fsc 0x0000.00000000
0x03 0x0006.009.0000554a 0x00c034be.025a.0c ---- 1 fsc 0x0000.00000000
seg/obj:块所在事物object id Csc:最后一次块清除时候的scn Itc:就是itl个数,这里是3,跟下面槽个数一致 Typ:数据块类型,1代表数据块,2代表索引块。 Xid:事务id。Xid组成:Undo Segment Number +Transaction Table Slot Number+ Wrap 0x0009.01e.0000556e:9.30. 21870 0x00c08d9d.0392.0b:12619165. 914.11 Flag:事务标志位,各个标志的含义分别是: B = this undo record contains the undo for this ITL entry T = transaction was still active at block cleanout SCN Lck:事务所影响的行数。因为都只更新了一行,所以值都是1. |
bdba: 0x01c0050a
data_block_dump,data header at 0x7fc2e8ab9a7c
===============
tsiz: 0x1f80
hsiz: 0x1a
pbl: 0x7fc2e8ab9a7c
76543210
flag=--------
ntab=1
nrow=4
frre=-1
fsbo=0x1a
fseo=0x1c
avsp=0x2
tosp=0x2
0xe:pti[0] nrow=4 offs=0
0x12:pri[0] offs=0x1c
0x14:pri[1] offs=0x7f5
0x16:pri[2] offs=0xfce
0x18:pri[3] offs=0x17a7
block_row_dump:
tab 0, row 0, @0x1c
tl: 2009 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 35
col 1: [2000]
78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78
tsiz: 数据区大小 hsiz: 数据块头大小 ntab:大于1代表rac nrow:数据块中的记录行数 frre=-1 ,-1代表索引 fsbo=0x1a 空闲空间起始位置 ,这里是26 fseo=0x1c 空闲空间结束位置,这里是28 avsp=0x2 可用空间。28-26=2,与bbed看到的26-24=2是一致的。 tosp=0x2 所有事务提交以后的可用空间。这里不会把分配的itl空间回收回去,因为itl还要保留来判断事务状态,所以还是2. 0xe:pti[0] nrow=4 代表4条记录 offs=0 偏移量是0 0x12:pri[0] offs=0x1c 第一条记录的偏移量在28的位置。 0x14:pri[1] offs=0x7f5 第二条记录的偏移量在2037的位置。 0x16:pri[2] offs=0xfce 第三条记录的偏移量在4046的位置。 0x18:pri[3] offs=0x17a7 第四条记录的偏移量在6055的位置。 因为每一条记录我都把字符宽度塞满了,所以每一条记录所占大小是一样的。通过偏移量的差就能看出来。 SQL> select 6055-4046,4046-2037,2037-28 from dual;
6055-4046 4046-2037 2037-28 ---------- ---------- ---------- 2009 2009 2009 下面这部分的计算在我另一篇博客里面有: http://blog.itpub.net/31480688/viewspace-2155667/ block_row_dump: tab 0, row 0, @0x1c tl: 2009 fb: --H-FL-- lb: 0x0 cc: 2 col 0: [ 2] c1 35 col 1: [2000] 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 78
|
enq: TX – allocate ITL entry解决措施
基本解决思路就是增加initrans和pctfree参数,可以单独调整一个,也可以一起调整。
1. alter table tablename initrans 50 | [pctfree 20]; 2. alter table tablename move; 3. rebuild index |
如果不move表,只单纯的alter table的话,那么只对后面插入的数据起作用。改变全表参数除了move之外,还有数据泵和在线重定义的方法。
ITL值和数据块blocksize的关系
Itl虽然可以设置一个很大的值,但是一般不会达到那个最大值,因为一个itl需要24bytes空间,所以最大不会超过block_size的48%,也就是说
Block_size | ITL个数 |
2048 | 41 |
4096 | 83 |
8192 | 169 |
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31480688/viewspace-2157157/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/31480688/viewspace-2157157/