2.oracle的dump理解二 Buffer Header和Block Header

来源:互联网 发布:如何使用海关数据 编辑:程序博客网 时间:2024/05/16 08:36

2.oracle的dump理解二 Buffer Header和Block Header

欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/51228474

上篇查看了BH的结构和说明。

此外,这里补充一下,其实也可以用alter session命令进行转储

ALTER SESSION SET EVENTS 'immediate tracename buffers level level';

这里的level有很多值,分别可以转储buffer cache中的不同的内容。

level的可选值包括:

1 只转储buffer header

2 在level 1的基础上再转储数据块头

3 在level 2的基础上再转储数据块内容

4 转储buffer header和hash chain

5 在level 1的基础上再转储数据块头和hash chain

6 在level 2的基础上再转储数据块内容和hash chain

8 转储buffer header和hash chain以及users/waiters链表

9 在level 1的基础上再转储数据块头、hash chain以及users/waiters链表

10 在level 2的基础上再转储数据块内容、hash chain以及users/waiters链表

例如:

SQL> alter session set events 'immediate tracename buffers level 1';

会话已更改。

1     小插曲

蛤蟆发现,用这个命令DUMP的BH头数量有57753个。

然后重新用ORADEBUGDUMP了一份,发现也是57753。

这个说明:两个命令DUMPBuffer Header大小事一致的,并无差异。

为了发现原因,蛤蟆重启了数据库,起来就立马重做一个DUMP。

发现BH只有5007个,那么终于弄明白了,BH 在数据库实例周期中是动态变化的。

因为当没有找到需要的buffer header时,oracle会发出I/O调用,到磁盘上的数据文件中获取数据块,并将该数据块的内容拷贝一份到buffer cache中的内存数据块里。

我们继续来看下,DUMP整个buffer cache后的样子吧。

SQL> oradebug dump buffers 2

或者

SQL>alter session set events 'immediatetrace name buffers level 2';

从TRACE文件中,首先是一个BH,然后可以看到如下:

Dump of memory from 0x000007FF192A4000 to0x000007FF192A6000

两地址相减刚好是2000,换成十进制就是8192,就是8K字节,就是一个BLOCK SIZE。

里面的内容不是给人看的如下:

…………………..

7FF192A4470 09727807 34100A0B 0972780734100A0B  [.xr....4.xr....4]

7FF192A4480 09727807 34100A0B FF02C10206C405FF  [.xr....4........]

7FF192A4490 FF11551F C3048001 02243807FFFF02C1  [.U.......8$.....]

7FF192A44A0 D2CE10FF 082264E5 2124D80F342C0A76  [.....d"...$!v.,4]

7FF192A44B0 80017755 80018001 0419002C455D04C3  [Uw......,.....]E]

………………….

2     Oracle数据块

数据块(Oracle Data Blocks),是Oracle最小的存储单位,Oracle数据存放在“块”中。一个块占用一定的磁盘空间。“块”是Oracle的“数据块”,不是操作系统的“块”。

  Oracle每次请求数据的时候,都是以块为单位。每次请求的数据是块的整数倍。如果Oracle请求的数据量不到一块,Oracle也会读取整个块。 “块”是Oracle读写数据的最小单位或者最基本的单位。

  块的标准大小由初始化参数DB_BLOCK_SIZE指定。具有标准大小的块称为标准块(Standard Block)。块的大小和标准块的大小不同的块叫非标准块(NonstandardBlock)。同一数据库中,Oracle9i及以上版本支持同一数据库中同时使用标准块和非标准块。Oracle允许指定5种非标准块(Nonstandard Block)。

  操作系统每次执行I/O的时候,是以操作系统的块为单位;Oracle每次执行I/O的时候,都是以Oracle的块为单位。Oracle数据块大小一般是操作系统块的整数倍。

块中存放表的数据和索引的数据,无论存放哪种类型的数据,块的格式都是相同的,块由块头(header/Common and Variable),表目录(Table Directory),行目录(Row Directory),空余空间(Free Space)和行数据(Row Data)五部分组成,

块头(header/Common and Variable):存放块的基本信息,如:块的物理地址,块所属的段的类型(是数据段还是索引段)。

3     Block header dump

最后有一个Blockheader的DUMP

Block header dump:  0x0040d0d8

 Object id on Block? Y

 seg/obj: 0x12 csc: 0x00.c1693  itc: 1  flg: - typ: 1 - DATA

    fsl: 0  fnx: 0x0 ver: 0x01

 

 Itl          Xid                  Uba         Flag Lck        Scn/Fsc

0x01   0x0008.015.00000310  0x01409480.0056.37  C---   0  scn 0x0000.000c1690

这里主要是ITL描述:

ITL(InterestedTransaction List)是Oracle数据块内部的一个组成部分,位于数据块头(block header),itl由xid,uba,flag,lck和scn/fsc组成,用来记录该块所有发生的事务,一个itl可以看作是一条事务记录。

如果事务已经提交,这个itl的位置就可以被反复使用了,有的时候也叫itl槽位。如果一个事务一直没有提交,那么,这个事务将一直占用一个itl槽位,itl里面记录了事务信息,回滚段的入口,事务类型等等。如果这个事务已经提交,那么,itl槽位中还保存的有这个事务提交时候的SCN号。

ITL个数其最小值为1,由参数initrans控制(由于兼容性的原因,oracle会在对象的存储块分配两个itl,所以initrans的最小值实际上为2),最大值为255,由参数maxtrans控制,最大值参数在10g以后不能被修改,itl是block级的概念,一个itl占用块46B的空间,参数initrans意味着块中除去block header外一部分存储空间无法被记录使用(46B*initrans),当块中还有一定的free space时,oracle可以使用free space构建itl供事务使用,如果没有了free space,那么,这个块因为不能分配新的itl,就可能发生itl等待。如果在并发量特别大的系统中,最好分配足够的itl个数,其实它并浪费不了太多的空间,或者,设置足够的pctfree,保证itl能扩展,但是pctfree有可能是被行数据给消耗掉的,如update,所以,也有可能导致块内部的空间不够而导致itl等待。

Xid:事务id,在回滚段事务表中有一条记录和这个事务对应

Uba:回滚段地址,该事务对应的回滚段地址

  第一段地址:回滚数据块的地址,包括回滚段文件号和数据块号

  第二段地址:回滚序列号

  第三段地址:回滚记录号

SELECT UBAFIL 回滚段文件号,UBABLK 数据块号,UBASQN 回滚序列号,UBAREC 回滚记录号 FROM v$transaction --查看UBA

SQL> select ubafil,ubablk,ubasqn,ubarecfrom v$transaction;

Flag:事务标志位。这个标志位就记录了这个事务的操作,各个标志的含义分别是:

----- = 事务是活动的,或者在块清除前提交事务

C--- = 事务已经提交并且清除了行锁定。

-B-- = this undo recordcontains the undo for this ITL entry

--U- = 事务已经提交(SCN已经是最大值),但是锁定还没有清除(快速清除)。

---T =当块清除的SCN被记录时,该事务仍然是活动的,块上如果有已经提交的事务,那么在clean ount的时候,块会被进行清除,但是这个块里面的事务不会被清除。

Lck:影响的记录数

Scn/Fsc:快速提交(Fast Commit Fsc)的SCN或者Commit SCN。

每条记录中的行级锁对应于Itl列表中的序号,即哪个事务在该记录上产生的锁。

3.1     ITL等待

 发生等待的场景:

1.超过maxtrans配置的最大ITL数

2.initrans不足,没有足够的free space来扩展ITL

解决方法:

1.maxtrans不足:高并发引起的:同一数据块上的事务量已经超出了其实际允许的ITL数。减少事务的并发量;长事务,在保证数据完整性的前提下,增加commit的频率,修改为短事务,减少资源占用事件。而对于OLAP系统来说(例如,其存在高并发量的数据录入模块),可以考虑增大数据块大小。

2.initrans不足:数据块上的ITL数量并没有达到MAX TRANS的限制,发生这种情况的表通常会被经常UPDATE,从而造成预留空间(PCTFREE)被填满。如果我们发现这类ITL等待对系统已经造成影响,可以通过增加表的INITRANS或者PCTFREE来解决(视该表上的并发事务量而定,通常,如果并发量高,建议优先增加INITRANS,反之,则优先考虑增加PCTFREE)。

如果是使用ALTER TABLE的方式修改这2个参数的话,只会影响新的数据块,而不会改变已有数据的数据块——要做的这一点,需要将数据导出/导入、重建表。 

3.2     行锁原理

Oracle的锁机制是一种轻量级的锁定机制,不是通过构建锁列表来进行数据的锁定管理,而是直接将锁作为数据块的属性,存储在数据块首部。这个是通过ITL来实现的,一个事务要修改块中的数据,必须获得该块中的一个itl(通过initrans预先分配的或者是通过free space构建的)。通过itl和undo segment header中的transaction table,可以知道事务处于活动阶段,还是已经完成。事务在修改块时(其实就是在修改行)会检查行中row header中的标志位,如果该标志位为0(该行没有被活动的事务锁住,这是可能要进行deferred block cleanout等工作),就把该标志位修改为事务在该块获得的itl的序号,这样当前事务就获得了对记录的锁定,然后就可以修改行数据了,这也就是oracle行锁实现的原理。

 

 

 

0 0
原创粉丝点击