Oracle block cleanout分析.docx
《Oracle block cleanout分析.docx》由会员分享,可在线阅读,更多相关《Oracle block cleanout分析.docx(23页珍藏版)》请在冰豆网上搜索。
Oracleblockcleanout分析
blockcleanout分析
问题1、什么是blockcleanout?
问题2、blockcleanout有分哪几种情况?
这些blockcleanout种类又是如何运作的?
问题3、如何进行手动blockcleanout?
首先我们先做下下面的三个实验,通过对redosize的变化情况来对blockcleanout有个感性认识:
altersystemsetDB_CACHE_SIZE=4M;--有512个8KB大小的数据块
实验1、
SQL>droptablett;
表已删除。
SQL>createtablett
2(xchar(2000),
3ychar(2000),
4zchar(2000));
表已创建。
SQL>setautotracetraceonlystatistics;
SQL>insertintott
2select'x','y','z'
3fromall_objects
4whererownum<=500;
已创建500行。
统计信息
----------------------------------------------------------
1405recursivecalls
2772dbblockgets
2327consistentgets
213physicalreads
3311036redosize--这里的redosize是对insert操作所做的redo
672bytessentviaSQL*Nettoclient
625bytesreceivedviaSQL*Netfromclient
4SQL*Netroundtripsto/fromclient
25sorts(memory)
0sorts(disk)
500rowsprocessed
//在事务还没有提交前就将被修改的数据块写进磁盘中去
SQL>ALTERSESSIONSETEVENTS'immediatetracenameflush_cache';
会话已更改。
SQL>commit;
提交完成。
SQL>select*fromtt;
已选择500行。
统计信息
----------------------------------------------------------
28recursivecalls
0dbblockgets
1084consistentgets
506physicalreads
36044redosize--事务递交前modifiedblock就被flush回硬盘,此时发生delayed--blockcleanout,所以redosize仍然很大
3024323bytessentviaSQL*Nettoclient
748bytesreceivedviaSQL*Netfromclient
35SQL*Netroundtripsto/fromclient
0sorts(memory)
0sorts(disk)
500rowsprocessed
SQL>select*fromtt;
已选择500行。
统计信息
----------------------------------------------------------
0recursivecalls
0dbblockgets
507consistentgets
0physicalreads
0redosize--由于进行过块清除,所以当再次进行访问这些数据块时,这些--被修改的数据块的块头中的事务的信息已经被清除掉,所以redosize=0
3024323bytessentviaSQL*Nettoclient
748bytesreceivedviaSQL*Netfromclient
35SQL*Netroundtripsto/fromclient
0sorts(memory)
0sorts(disk)
500rowsprocessed
实验2、
SQL>droptablett;
SQL>createtablett
2(xchar(2000),
3ychar(2000),
4zchar(2000));
表已创建。
SQL>setautotracetraceonlystatistics;
SQL>insertintott
2select'x','y','z'
3fromall_objects
4whererownum<=500;
已创建500行。
统计信息
----------------------------------------------------------
1399recursivecalls
2773dbblockgets
2281consistentgets
194physicalreads
3311368redosize--事务递交时对insert操作进行了redo,也进行了快速块清除,所
--以redosize很大
675bytessentviaSQL*Nettoclient
625bytesreceivedviaSQL*Netfromclient
4SQL*Netroundtripsto/fromclient
25sorts(memory)
0sorts(disk)
500rowsprocessed
SQL>commit;
提交完成。
SQL>select*fromtt;
已选择500行。
统计信息
----------------------------------------------------------
28recursivecalls
0dbblockgets
571consistentgets
0physicalreads
0redosize--事务递交时已经进行了快速块清除,将所有的被修改的数据--块的事务信息都已经清除掉,所以redosize=0
3024323bytessentviaSQL*Nettoclient
748bytesreceivedviaSQL*Netfromclient
35SQL*Netroundtripsto/fromclient
0sorts(memory)
0sorts(disk)
500rowsprocessed
实验3、
SQL>droptablett;
表已删除。
SQL>createtablett
2(xchar(2000),
3ychar(2000),
4zchar(2000));
表已创建。
SQL>setautotracetraceonlystatistics;
SQL>insertintott
2select'x','y','z'
3fromall_objects
4whererownum<=10000;
已创建10000行。
统计信息
----------------------------------------------------------
4128recursivecalls
48003dbblockgets
18138consistentgets
2physicalreads
65458116redosize--事务递交时对insert操作进行了redo,也进行了快速块清除680bytessentviaSQL*Nettoclient
626bytesreceivedviaSQL*Netfromclient
4SQL*Netroundtripsto/fromclient
25sorts(memory)
0sorts(disk)
10000rowsprocessed
SQL>commit;
提交完成。
SQL>select*fromtt;
已选择10000行。
统计信息
----------------------------------------------------------
28recursivecalls
0dbblockgets
15767consistentgets
0physicalreads
409092redosize--事务递交时已经进行了快速块清除,但是并没有将所有被修改的
--数据块的事务信息清除掉,所以在第一次对该表进行查询时需要--将剩余的被修改的数据块上的事务信息清除掉,所以redosize>0
60477113bytessentviaSQL*Nettoclient
7711bytesreceivedviaSQL*Netfromclient
668SQL*Netroundtripsto/fromclient
0sorts(memory)
0sorts(disk)
10000rowsprocessed
SQL>select*fromtt;
已选择10000行。
统计信息
----------------------------------------------------------
0recursivecalls
0dbblockgets
10011consistentgets
0physicalreads
0redosize
60477113bytessentviaSQL*Nettoclient
7711bytesreceivedviaSQL*Netfromclient
668SQL*Netroundtripsto/fromclient
0sorts(memory)
0sorts(disk)
10000rowsprocessed
从上面的三个实验中可以看出redosize的变化,redosize的变化中除了DML操作所产生的redo所产生的redosize变化,还有来源于块清除(blockcleanout)操作影响redosize的变化。
问题1、什么是blockcleanout
blockcleanout是指把一个块中的数据从dirty变为clean,等于告诉后面的人,这个块里面的数据是干净的,可以放心的使用,本质上是更改blockheader中的一个标志位。
即删除被修改的数据块块头上的事务和数据锁定信息。
数据块块头中的事务和数据锁定信息如下部分:
Blockheaderdump:
0x0080000a
ObjectidonBlock?
Y
seg/obj:
0xd415csc:
0x00.1ea33citc:
3flg:
-typ:
1-DATA
fsl:
0fnx:
0x0ver:
0x01
ItlXidUbaFlagLckScn/Fsc
0x010xffff.000.000000000x00000000.0000.00C---0scn0x0000.001ea33c
0x020x0002.008.000004890x01c0001c.01ca.1f--U-1fsc0x0000.001ea453
0x030x0000.000.000000000x00000000.0000.00----0fsc0x0000.00000000
。
。
。
。
tl:
207fb:
--H-FL--lb:
0x2cc:
2
解释下相关的标识表示的信息:
CSC:
即CleanoutSCN,它是在insert操作事务中产生的。
TheSCNatwhichthelastfullcleanoutwasperformedontheblock
block最后一次做Totalblockcleanout时所确定的scn值
Flag:
事务标志位。
各个标志的含义分别是:
C---=transactionhasbeencommittedandlockscleanedout
-B--=thisundorecordcontainstheundoforthisITLentry
--U-=transactioncommitted(maybelongago);SCNisanupperbound
---T=transactionwasstillactiveatblockcleanoutSCN
事务标志是----,这是为什么呢?
一般是由于在commit之前进行了buffercacheflush,也就是说,oracle进程在改写数据块时,该事务还未提交,也未回滚,所以标志为空。
而假如将buffercacheflush放在commit之后,该标致就为--U-,即事务已经提交,但是相应的锁并没有清除(下面的例子可以验证)。
所以,看到后面的Lck位(行级锁数目)为1(因为我们修改了1条记录)。
Lb:
每条记录中的行级锁对应Itl条目lb:
都是0x02。
即Itl中的第二条。
补充:
Xid:
事务id,在回滚段事务表中有一条记录和这个事务对应
Uba:
回滚段地址,该事务对应的回滚段地址
第一段地址:
回滚数据块的地址,包括回滚段文件号和数据块号
第二段地址:
回滚序列号
第三段地址:
回滚记录号
SELECTUBAFIL回滚段文件号,UBABLK数据块号,UBASQN回滚序列号,UBAREC回滚记录号FROMv$transaction--查看UBA
Flag:
事务标志位。
这个标志位就记录了这个事务的操作,各个标志的含义分别是:
-----=事务是活动的,或者在块清除前提交事务
C---=事务已经提交并且清除了行锁定。
-B--=thisundorecordcontainstheundoforthisITLentry
--U-=事务已经提交(SCN已经是最大值),但是锁定还没有清除。
(快速清除)
---T=当块清除的SCN被记录时,该事务仍然是活动的,块上如果有已经提交的事务,那么在cleanount的时候,块会被进行清除,但是这个块里面的事务不会被清除。
Lck:
影响的记录数
Scn/Fsc:
快速提交(FastCommitFsc)的SCN或者CommitSCN。
每条记录中的行级锁对应于Itl列表中的序号,即哪个事务在该记录上产生的锁。
问题2、blockcleanout分类
blockcleanout(块清除)分2种:
1、快速提交清除(fastcommitcleanout):
每个事务中被修改的数据块中有10%DB_CACHE_SIZE的大小是在事务提交的时候进行了块清除,这种块清除活动叫快速提交清除;
快速提交所做的操作:
当一个事务访问一个数据块时,它会占用数据块Itl中的一个条目,记录下事务ID(Xid)、该事务对该数据块操作时使用的回滚块地址(Uba)和在该数据块上产生的行级锁的数量,并在对应数据行上打上行锁标志,与Itl对应。
当提交时,设置Itl中的事物标志为U,并写入一个快速提交SCN(Fsc),但并不清除锁标志。
补充:
oracle有一个modifiedblocklist结构,用来记录每个transaction更改过的block,每个transaction大约可以记录10%buffercache这多的modifiedblock。
这部分block就是当发生commit的时候,oracle可以根据modifiedblocklist定位到那些块并做fastcommitcleanout。
当发生fastcommitcleanout,系统将transaction提交时刻的scn作为commitscn,更新block上itl和undosegmentheader的Transactiontable的slot上的scn,并修改blockscn,三者是一致的。
等下一次update该数据块时,才会清理Rowlockslb标志位,ITLlck标志位。
csc
在第一次insert时有一个csc;
在upate后,commit前无变化;
在commit后无变化;
在select*后无变化;
2、延迟块清除(delayedblockcleanout):
1)如果一个事务那些超过10%的DB_CACHE_SIZE大小的部分将被留到下一次对这些数据块访问时完成;
2)还有一种情况是当事务还没有commit提交时,被修改的数据块就已经被写入磁盘中去,然后当发生commit时,oracle不会将被修改的数据块重新读入磁盘也不会做块清除工作,而是留到下次对这些数据块访问时才做块清除工作;
补充:
1.
发生delayedblockcleanout的时候,之前的transactioncommit更新的只是undosegmentheaderTransactiontable上的slotscn,而并未做block上的更新,等待下次使用此block的时候,更新blockscn和itl状态。
blockscn和itl的更新又分2种情况:
(1)当不产生slot重用的时候,delayedblockcleanout时,根据Transactiontable里面的信息,更新blockscn和itl上的Scn/Fsc为transaction曾经提交时候的scn。
(2)当产生slot重用的时候,更新对应itl上scn(也叫upperboundscn,上限)为undosegment上的controlscn(从回滚段中找到的最小事务scn),而blockscn为delayedblockcleanout发生时刻的scn。
2.
Csc(cleanoutscn)
在第一次insert时有一个csc;
在upate后,flush后变化了;
在flush后,commit前无变化;
在select*后变化了;
3.
一个block含有三个scn,blockscn;csc;commitscn(itl上)
3、测试案例
下面分别对blockcleanout的两种分类三种情况进行测试证明,对oralce做块清除时数据块的状态做跟踪分析:
搭建测试环境如下:
SQL>droptabletest;
droptabletest*
第1行出现错误:
ORA-00942:
表或视图不存在
SQL>createtabletest
2(idint,
3namechar(600))
4pctfree99pctused1;
表已创建。
SQL>altersystemsetDB_CACHE_SIZE=32M;
系统已更改。
SQL>droptabletest;
表已删除。
SQL>createtabletest
2(idint,
3namechar(600))
4pctfree99pctused1;
表已创建。
SQL>insertintotest
2selectobject_id,object_name
3fromall_objects
4whererownum<1000;
已创建999行。
统计信息
----------------------------------------------------------
3128recursivecalls
5151dbblockgets
4881consistentgets
8physicalreads
1170744redosize
680bytessentviaSQL*Nettoclient
621bytesreceivedviaSQL*Netfromclient
4SQL*Netroundtripsto/fromclient
55sorts(memory)
0sorts(disk)
999rowsprocessed
SQL>selectrownum,dbms_rowid.rowid_relative_fno(rowid)"file#",dbms_rowid.rowid_block_number(rowid)"block#"
2fromtest
3;
ROWNUMfile#block#
------------------------------
12994
22995
32996
42997
52998
62999
721000
821001
921002
1021003
1121004
1221005
1321006
1421007
1521008
1621009
1721010
1821011
1921012
2021013
.....
ROWNUMfile#block#
------------------------------
9872868
9882869
9892870
9902871
9912872
9922873
9932874
9942875
9952876
9962877
9972878
9982879
9992880
999rowsselected
SQL>selectmax(dbms_rowid.rowid_relative_fno(rowid))"maxfile#",
2max(dbms_rowid.rowid_block_number(rowid))"maxblock#",
3min(dbms_rowid.rowid_relative_fno(rowid))"mi