oracle是以数据块为单位来管理存储空间的。数据块是数据中的最小单位。标准数据块大小使用db_block_size初始参数指定,也可以指定5种非标准块大小。为了最大限度的避免不必要的i/o,数据块的大小应该是多个操作系统块大小。数据块的格式无论是块包含的表,索引,或是cluster,结构都是相似的。
header :头部包含一般的数据块信息,比如数据块的地址和段的类型
table directory:这部分包含块中表的信息
row directory:包含块中存放的实际的行信息,包括每个行片段的地址。
在块中row directory分配后,行被删除的时候空间不会被回收,如,一个块曾经有50行分配了100字节空间,现在没有记录,oracle再次插入的时候会重用这些空间。
开销:数据块头,表directory,行directory都是开销,一个开销是固定大小的,总的开销是可变的,一般的,固定开销和可变开销总的是84到107个字节。
行数据:这部分包含了数据,数据行可以有多个块。
自由空间:自由空间用来插入与更新行。对每个insert,update delete都要求事务条目,需要的空间大小依赖与操作系统,对大多数的操作系统来说是23字节。
自由空间的管理:空间的管理可以使自动的,也可以是手动的。
自动管理的段,使用位图跟踪空间的使用,当创建本地管理的表空间是,创建自动管理段。
看到数据字典管理extent与自动段管理是不能同时使用的,在本地管理的system表空间的数据库中无法创建字典管理的表空间。
自由空间的可用及优化:
两种类型的操作能增大自由空间,delete与update,这些自由空间对后续的insert是可用的在如下的条件中:
1如果insert是在同一个事务中。
2insert不在同一个事务中,仅在事务提交和空间紧缺的情况下才可以使用空闲空间。
释放的空间也许不是连续的。数据库只有在下面2中情况下会整合空间,insert,或update要在块中保存数据,这个块有足够空间但由于有碎片导致不能保存。数据库只在这种情况下来做压缩,是因为这种操作会降低数据库的性能。
pctfree,pctused
在手工管理的表空间中,pctfree,pctused可以控制insert和update使用的空间空间。
pctfree参数设置数据块用来update保存空间的最小百分比。比如要是设置了pctfree 20代表者有20%的空间空闲出来为了后续的update操作。
这个20%只是对已存在的数据的update而准备的。
pctused:设置了数据块的最小的百分比用来新数据的插入。在数据块增长到pctfree的限制的时候,oracle认为这个块不可用,数据块的使用降低到pctused后,认为这个块是可用的。比如指定pctused 40,直到数据库中的使用降到39%或更低,才能继续向块中插入数据。
一个新的数据块,可以使用的空间是数据块的大小减去块消耗和pctfree占用的空间。存储参数initial,next pctincrease和minextents对本地管理表空间在表空间级是无法指定的。但是可以再段级别指定。
可以使用下面的语句来回收未使用的extents
alter table table_name deallocate unused;
在临时表段中的extents
当oracle使用完临时段后,oralce自动的删除临时段,并返回空间给表空间。一个单独的排序会在临时表空间中分配他自己的临时段。对多个排序可以使用排序段中为大量排序指定的排序段,这些排序段只为实例分配一次,在排序完后他们不会返回给数据库,但是对别的多个排序可以重复使用。
dump数据块
数据库中存在下面的表,使用alter system dump datafile 4 block 1148;生成trc
SQL> select * from scott.test;
ID NAME
-------------------------------------------------------------------------------- --------------------
12.2 bai
123 xiao
456 yu
*** SERVICE NAME:(SYS$USERS) 2014-08-29 11:54:51.885
*** SESSION ID:(151.37) 2014-08-29 11:54:51.885
Start dump data blocks tsn: 4 file#: 4 minblk 1148 maxblk 1148
buffer tsn: 4 rdba: 0x0100047c (4/1148)
scn: 0x0000.0010a08c seq: 0x05 flg: 0x06 tail: 0xa08c0605
frmt: 0x02 chkval: 0x9b6e type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
********************************************************************
rba是相对数据块地址(用4个字节32位来表示,前10位为相对数据文件号,后22位为块号。01400010=0000 0001 0100 0000 0000 0000 0001 0000(二进制)
我们看到前10位转换成十进制就是5,后22位转换成十进制就是16。),scn:scn号总共占用6个字节,前2个字节表示SCN Wrap,后4个字节表示SCN
Base,seq:scn序列号,tail:维护数据一致性验证块在开始到结束是同一个版本(由scn的低二字节+块类型+scn序列号)
frmt块的格式 chkval可选的检查值 如果db_block_checksum=true,type块类型
***********************************************************************
Dump of memory from 0x05782200 to 0x05784200
5782200 0000A206 0100047C 0010A08C 06050000 [....|...........]
5782210 00009B6E 00000001 0000C9B4 00109FF5 [n...............]
5782220 00000000 00320002 01000479 001B0006 [......2.y.......]
5782230 0000016F 008003EA 00040128 00002003 [o.......(.... ..]
5782240 0010A08C 00000000 00000000 00000000 [................]
5782250 00000000 00000000 00000000 00000000 [................]
5782260 00000000 00030100 0018FFFF 1F5E1F76 [............v.^.]
5782270 00001F5E 1F8C0003 1F761F80 00000000 [^.........v.....]
5782280 00000000 00000000 00000000 00000000 [................]
Repeat 500 times
57841D0 00000000 00000000 012C0000 75790202 [..........,...yu]
57841E0 36353403 0402012C 6F616978 33323103 [.456,...xiao.123]
57841F0 0302012C 04696162 322E3231 A08C0605 [,...bai.12.2....]
Block header dump: 0x0100047c
Object id on Block? Y
seg/obj: 0xc9b4 csc: 0x00.109ff5 itc: 2 flg: E typ: 1 - DATA
brn: 0 bdba: 0x1000479 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0006.01b.0000016f 0x008003ea.0128.04 --U- 3 fsc 0x0000.0010a08c
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
***********************************************************************************
csc:块最后清除时的scn ,itc事务槽数,type 1是data 2是index,xid事务id(undoseg.slot.wrap),uba undo地址(undodba.seqno,recordno)
flag c=commit u=commit upper bound; t=active at csc lock被这个事务影响的行数,scn/fsc scn=scn of commited tx fsc=free space credit
select xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn,ubarec from v$transaction; 可以查这个来对比
Flag:事务标志位。这个标志位就记录了这个事务的操作状态,各个标志的含义分别是:
C = transaction has been committed and locks cleaned out --事物已经提交,锁已经被清除
B = this undo record contains the undo for this ITL entry
U = transaction committed (maybe long ago); SCN is an upper bound --事物已经提交,但是锁还没有清除
T = transaction was still active at block cleanout SCN --块清除的SCN被记录时,该事务仍然是活动的,块
上如果有已经提交的事务,那么在clean ount的时候,块会被进行清除,但是这个块里面的事务不会被清除。
Lck:表示这个事务所影响的行数。我们看到01号事物槽Lck为0,因为该事物槽中的事物Flag为C,证明该事物
已经提交,锁也被清楚掉了,该事物槽可以被重用了。02号事物槽Lck为1,是因为我对第一行做了一个更新,
并且没有提交,Flag为----说明该事物是活动的。
Scn/Fsc:Commit SCN或者快速提交(Fast Commit Fsc)的SCN。
每条记录中的行级锁对应Itl条目lb,对应于Itl列表中的序号,即那个事务在该记录上产生的锁。
对于Oracle来说,对于一个事务,可以是快速提交、也可以是延迟提交,目的都是为了提高提交的速度。提交以后,oracle需要对ITL事务槽、每一行的锁定标记进行清除。如果是快速提交,那么在提交的时候,会将事务表和每一个数据块的ITL槽进行清除。但是锁定标记可能没有清除,等下次用到的时候再进行清除。如果是延迟提交,那么在提交的时候,只是将事务表进行清除,并没有对ITL事务槽进行清除,每一行的锁定标记也没有清除。因此C和U的情况特别多。块清除的过程并不包括每个行的锁定标记的清除,主要指的是ITL的清除。
注意:
1、事务槽中首先记录的是Xid和Uba,只有在提交以后,当对这个数据块进行cleanout的时候,才会更新Flag和Scn。因此Oracle总是以事务表中对这个数据块的Scn以及Flag为准。
2、一个事务开始以后,在一个数据块上得到一个事务槽,那么在这个事务提交以前,这个事务槽会一直占用,直到这个事务提交释放这个事务槽。
3、只有在已经提交以后,这个itl事务槽中的scn才会有数值。
4、事务是否已经提交、事务对应的SCN,这些信息都是以回滚段事务表中的为主,事务槽中的不准确
5、事务槽中的事务id和uba地址是准确的
6、事务槽1中的事务id和回滚段中的事务id肯定不是一样的,不同回滚段中的事务id也一定不一样。
***********************************************************************************
data_block_dump,data header at 0x5782264
===============
tsiz: 0x1f98
hsiz: 0x18
pbl: 0x05782264
bdba: 0x0100047c
76543210
flag=--------
ntab=1
nrow=3
frre=-1
fsbo=0x18
fseo=0x1f76
avsp=0x1f5e
tosp=0x1f5e
0xe:pti[0] nrow=3offs=0
0x12:pri[0] offs=0x1f8c
0x14:pri[1] offs=0x1f80
0x16:pri[2] offs=0x1f76
block_row_dump:
tab 0, row 0, @0x1f8c
tl: 12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] 62 61 69
col 1: [ 4] 31 32 2e 32
tab 0, row 1, @0x1f80
tl: 12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 4] 78 69 61 6f
col 1: [ 3] 31 32 33
tab 0, row 2, @0x1f76
tl: 10 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] 79 75
col 1: [ 3] 34 35 36
end_of_block_dump
End dump data blocks tsn: 4 file#: 4 minblk 1148 maxblk 1148
***************************************************************************
tsiz:数据区总大小 hsiz数据头大小 pbl指向持有该块的buffer指针 bdba数据块的相对地址 flag n=pctfree hit; f=不放到空闲列表上,k=可刷新簇键 ntab表行数 nrow行数量,frre第一个索引的条目,如果是-1说明需要创建索引,fsbo开始偏移的自由空间,fseo结束便宜的自由空间。avsp块中可用空间。tosp 当tx提交后总的可用空间 nrow第一个表行数。
lb锁字节 cc在这个行片中的列数,fb flag byte,t1行大小,col column数据。
*******************************************************************************
什么是块损坏
当dbms读取或写数据块到数据库中的时候,做下面的操作
1检查块的版本
2在内存中的dba值与块缓存中的dba
3如果启用了的话,执行block检查
延迟块清除
如果一次修改的块,没有超过了缓冲区缓存大小的10%,并且这些块在内存中,则commit时,会清除块上的事务信息,
否则,就不会理会它,直到下次访问这些块时,再清除块中的事务信息,这就是延迟块清除.
因为这个Select修改了块的事务信息,所以就会产生Redo.
下面是根据ITPUB上的资料和我的理解整理的关于块清除时SCN的填写,以及什么情况产生”快照太旧”的错误.
延迟清除的块的下一个读者,首先根据块中的记录的回滚信息去查找回滚段中记录的commit时的SCN,
但回滚段可能已回绕,找不到提交时的scn了,
但是,从回滚段中可以得到一个最小的提交scn并且该事务已经提交肯定小于这个从回滚段中还存在的最小scn。
那么oracle给这个块清除的事务分配一个从回滚段中找到的最小事务scn。
这虽然不准确,但是是安全的,对于数据访问也不构成影响。所以叫 upper bound ,猜测的一个scn的上限。
延迟清除的块在被select 时,如果读的select 的scn 比这个回滚段里面最小的scn 还要小的话(回滚段已回绕),那么在回滚段里面找不到数据了,oracle 就没有办法判断select 的SCN 与被要清除的数据块的大小关系,于是ora-01555就出现了,这个时候oracle 就不知道数据块里面的数据是不是是查询时刻需要的数据.
如果select scn 大于回滚段里面最小的scn 的话,那么oracle 就使用这个最小的scn 来做为这个事务的 scn 来更新块的itl ,从而完成块的清除.
参考文章
http://czmmiao.diandian.com/post/2012-04-23/18360218
http://ftc007.blog.163.com/blog/static/19657165020125194214749/