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字节。

自由空间的管理:空间的管理可以使自动的,也可以是手动的。

自动管理的段,使用位图跟踪空间的使用,当创建本地管理的表空间是,创建自动管理段。

数据块_oracle_02

数据块_数据_03

看到数据字典管理extent与自动段管理是不能同时使用的,在本地管理的system表空间的数据库中无法创建字典管理的表空间。

自由空间的可用及优化:

两种类型的操作能增大自由空间,delete与update,这些自由空间对后续的insert是可用的在如下的条件中:

1如果insert是在同一个事务中。

2insert不在同一个事务中,仅在事务提交和空间紧缺的情况下才可以使用空闲空间。

释放的空间也许不是连续的。数据库只有在下面2中情况下会整合空间,insert,或update要在块中保存数据,这个块有足够空间但由于有碎片导致不能保存。数据库只在这种情况下来做压缩,是因为这种操作会降低数据库的性能。

pctfree,pctused

在手工管理的表空间中,pctfree,pctused可以控制insert和update使用的空间空间。

pctfree参数设置数据块用来update保存空间的最小百分比。比如要是设置了pctfree 20代表者有20%的空间空闲出来为了后续的update操作。

数据块_oracle_04

这个20%只是对已存在的数据的update而准备的。

pctused:设置了数据块的最小的百分比用来新数据的插入。在数据块增长到pctfree的限制的时候,oracle认为这个块不可用,数据块的使用降低到pctused后,认为这个块是可用的。比如指定pctused 40,直到数据库中的使用降到39%或更低,才能继续向块中插入数据。

数据块_回滚_05

一个新的数据块,可以使用的空间是数据块的大小减去块消耗和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 ,从而完成块的清除.