这次测试是在MSSM方式下进行的:
SQL> desc t;
名称 是否为空? 类型
----------------------------------------- -------- ----------------------------
ID NUMBER(38)
NAME CHAR(1000)
SQL> select num_rows,blocks,empty_blocks,num_freelist_blocks
2 from dba_tables where table_name='T' and wner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS
---------- ---------- ------------ -------------------
0 0 7 0
SQL> select pct_used,pct_free from user_tables where table_name='T';
PCT_USED PCT_FREE
---------- ----------
50 50
SQL> show parameter db_block_size;
NAME TYPE VALUE
------------------------------------ ----------- -----------------------------
db_block_size integer 8192
对于这样一个结构的表,我们已经可以推断一个block中最多只能容纳3行的数据
SQL> insert into t values (1,'a');
已创建 1 行。
SQL> insert into t values (2,'b');
已创建 1 行。
SQL> insert into t values (3,'c');
已创建 1 行。
SQL> insert into t values (4,'d');
已创建 1 行。
SQL> commit;
提交完成。
SQL> analyze table t compute statistics;
表已分析。
SQL> select id,rowid from t;
ID ROWID
---------- ------------------
1 AAABnRAAJAAAAAKAAA
2 AAABnRAAJAAAAAKAAB
3 AAABnRAAJAAAAAKAAC
4 AAABnRAAJAAAAALAAA
SQL> select extent_id,block_id,bytes,blocks from dba_extents
2 where segment_name='T' and wner='SYS';
EXTENT_ID BLOCK_ID BYTES BLOCKS
---------- ---------- ---------- ----------
0 9 65536 8
SQL> select num_rows,blocks,empty_blocks,num_freelist_blocks
2 from dba_tables where table_name='T' and wner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS
---------- ---------- ------------ -------------------
4 2 5 1
SQL> insert into t values (5,'e');
已创建 1 行。
SQL> insert into t values (6,'f');
已创建 1 行。
SQL> commit;
提交完成。
SQL> analyze table t compute statistics;
表已分析。
SQL> select num_rows,blocks,empty_blocks,num_freelist_blocks
2 from dba_tables where table_name='T' and wner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS
---------- ---------- ------------ -------------------
6 2 5 1
SQL> insert into t values (7,'g');
已创建 1 行。
SQL> insert into t values (8,'h');
已创建 1 行。
SQL> insert into t values (9,'i');
已创建 1 行。
SQL> commit;
提交完成。
SQL> analyze table t compute statistics;
表已分析。
SQL> select id ,rowid,ROWNUM,dbms_rowid.rowid_block_number(rowid) block_number from t;
ID ROWID ROWNUM BLOCK_NUMBER
---------- ------------------ ---------- ------------
1 AAABnRAAJAAAAAKAAA 1 10
2 AAABnRAAJAAAAAKAAB 2 10
3 AAABnRAAJAAAAAKAAC 3 10
4 AAABnRAAJAAAAALAAA 4 11
5 AAABnRAAJAAAAALAAB 5 11
6 AAABnRAAJAAAAALAAC 6 11
7 AAABnRAAJAAAAAMAAA 7 12
8 AAABnRAAJAAAAAMAAB 8 12
9 AAABnRAAJAAAAAMAAC 9 12
已选择9行。
SQL> select num_rows,blocks,empty_blocks,num_freelist_blocks
2 from dba_tables where table_name='T' and wner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS
---------- ---------- ------------ -------------------
9 3 4 1
每insert三行的block使用率已经达到我们pctfree=50的限制(8K*(1-50%)=4k),这里的块为什么还是1而不是0呢,原则上讲他应该从freelist里release出去了,为什么会这样?
来看下面的步骤进行推倒解释,,转储一下我们的segment header(Oracle会在每个段,利用一个block来记录segment header信息,其中包括freelist)
SQL> alter system dump datafile 9 block 9;
系统已更改。
Start dump data blocks tsn: 8 file#: 9 minblk 9 maxblk 9
buffer tsn: 8 rdba: 0x02400009 (9/9)
scn: 0x0000.000deedc seq: 0x02 flg: 0x00 tail: 0xeedc1002
frmt: 0x02 chkval: 0x0000 type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 7
last map 0x00000000 #maps: 0 offset: 4128
Highwater:: 0x0240000d ext#: 0 blk#: 3 ext size: 7
#blocks in seg. hdr's freelists: 1
#blocks below: 3
mapblk 0x00000000 offset: 0
Unlocked
Map Header:: next 0x00000000 #extents: 1 obj#: 6609 flag: 0x40000000
Extent Map
-----------------------------------------------------------------
0x0240000a length: 7
nfl = 1, nfb = 1 typ = 1 nxf = 1 ccnt = 3
SEG LST:: flg: USED lhd: 0x0240000c ltl: 0x0240000c
XCT LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 xid: 0x0000.000.00000000
注意SEG LST:: flg: USED lhd: 0x0240000c ltl: 0x0240000c 其中的lhd 0x0240000c对应的十进制的value为:37748748
那么我们可以看看
其实这个地址就是rdba地址:
SQL> define myV=37748748
SQL> select dbms_utility.data_block_address_file(&myV) "file",dbms_utility.data_block_address_block(&myv) "block" from dual;
原值 1: select dbms_utility.data_block_address_file(&myV) "file",dbms_utility.data_block_address_block(&myv) "block" from dual
新值 1: select dbms_utility.data_block_address_file(37748748) "file",dbms_utility.data_block_address_block(37748748) "block" from dual
file block
---------- ----------
9 12
我们可以知道最后在feelists上的块是block 12,也就是说block 12是最后一个满了的block,虽然块的状态是full,但是在没有新的block加入到freelists上之前这个block是不会从freelists上消失的。
我们继续insert,这个时候会分配一个新的block到freelist上。
SQL> insert into t values (10,'j');
已创建 1 行。
SQL> commit;
提交完成。
SQL> analyze table t compute statistics;
表已分析。
SQL> select id ,rowid,ROWNUM,dbms_rowid.rowid_block_number(rowid) block_number from t;
ID ROWID ROWNUM BLOCK_NUMBER
---------- ------------------ ---------- ------------
1 AAABnRAAJAAAAAKAAA 1 10
2 AAABnRAAJAAAAAKAAB 2 10
3 AAABnRAAJAAAAAKAAC 3 10
4 AAABnRAAJAAAAALAAA 4 11
5 AAABnRAAJAAAAALAAB 5 11
6 AAABnRAAJAAAAALAAC 6 11
7 AAABnRAAJAAAAAMAAA 7 12
8 AAABnRAAJAAAAAMAAB 8 12
9 AAABnRAAJAAAAAMAAC 9 12
10 AAABnRAAJAAAAANAAA 10 13
SQL> select num_rows,blocks,empty_blocks,num_freelist_blocks
2 from dba_tables where table_name='T' and wner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS
---------- ---------- ------------ -------------------
10 4 3 1
SQL> alter system dump datafile 9 block 9;
系统已更改。
Start dump data blocks tsn: 8 file#: 9 minblk 9 maxblk 9
buffer tsn: 8 rdba: 0x02400009 (9/9)
scn: 0x0000.000df06b seq: 0x02 flg: 0x04 tail: 0xf06b1002
frmt: 0x02 chkval: 0x5da2 type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 7
last map 0x00000000 #maps: 0 offset: 4128
Highwater:: 0x0240000e ext#: 0 blk#: 4 ext size: 7
#blocks in seg. hdr's freelists: 1
#blocks below: 4
mapblk 0x00000000 offset: 0
Unlocked
Map Header:: next 0x00000000 #extents: 1 obj#: 6609 flag: 0x40000000
Extent Map
-----------------------------------------------------------------
0x0240000a length: 7
nfl = 1, nfb = 1 typ = 1 nxf = 1 ccnt = 4
SEG LST:: flg: USED lhd: 0x0240000d ltl: 0x0240000d
XCT LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 xid: 0x0000.000.00000000
这里的rdba:0x0240000d 对应的就是block 13,也就说freelist上的那一个block就是block 13
只有在hwm下的没有block的情况下,freelist中的block数量才能归0.
SQL> truncate table t;
表已截掉。
SQL> analyze table t compute statistics;
表已分析。
SQL> select num_rows,blocks,empty_blocks,num_freelist_blocks
2 from dba_tables where table_name='T' and wner='SYS';
NUM_ROWS BLOCKS EMPTY_BLOCKS NUM_FREELIST_BLOCKS
---------- ---------- ------------ -------------------
0 0 7 0
基本上就是这样