插入(Insert),更新(Update),刪除(Delete)操作對數據塊的影響
創建一個名爲test的表,並向裏面插入三條記錄用於測試。用dba用戶登錄創建PL/SQL過程show_space,用於顯示某個表使用block的信息。show_space的使用參考文章:http://blog.csdn.net/huang_tg/archive/2010/07/09/5724499.aspx
SQL> create table test
2 (sno varchar2(10),
3 sname varchar2(20));
表已創建。
SQL> insert into test values ('001','huang');
SQL> insert into test values ('002','ting');
SQL> insert into test values ('003','guang');
SQL> commit;
提交完成。
SQL> set serveroutput on
SQL> exec show_space('TEST');
Total Blocks............................3
Total Bytes.............................12288
Unused Blocks...........................1
Unused Bytes............................4096
Last Used Ext FileId....................1
Last Used Ext BlockId...................61573
Last Used Block.........................2
PL/SQL 過程已成功完成。
SQL> alter system dump datafile 1 block 61574;
系統已更改。
data_block_dump
===============
tsiz: 0xfa0
hsiz: 0x18
pbl: 0x0296105c
bdba: 0x0040f086
flag=-------------
ntab=1
nrow=3
frre=-1
fsbo=0x18
fseo=0xf7a
avsp=0xf62
tosp=0xf62
0xe:pti[0] nrow=3 offs=0 --本塊存在3條記錄
0x12:pri[0] offs=0xf93 --記錄的起始物理位置
0x14:pri[1] offs=0xf87
0x16:pri[2] offs=0xf7a
block_row_dump:
tab 0, row 0, @0xf93 --第一行數據開始的物理地址
tl: 13 fb: --H-FL-- lb: 0x1 cc: 2 --lb:表示屬於XID 0x1 cc:表示有2字段
col 0: [ 3] 30 30 31 --字段1長度爲3,數據30 30 31
col 1: [ 5] 68 75 61 6e 67 --字段2長度爲5,數據68 75 51 6e 67
tab 0, row 1, @0xf87
tl: 12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] 30 30 32
col 1: [ 4] 74 69 6e 67
tab 0, row 2, @0xf7a
tl: 13 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] 30 30 33
col 1: [ 5] 67 75 61 6e 67
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 61574 maxblk 61574
1.插入(Insert)數據對數據塊的影響
數據在oracle數據庫中的存儲是從block的底部開始的,遵循從下到上的規則。當一個新行被插入時,oracle首先搜索freelist (數據塊中使用的空間未達到PCTUSED設置的值)中的空閒塊,如果找到則插入數據。沒有找到則使用HWM指向的數據塊(block),同時移動HWM,使其指向下一個未使用過的數據塊。如果行數據過大,一個數據塊裝不下,那麼就會產生行鏈接。以下是向測試表中插入兩條記錄後數據塊的變化:
SQL> insert into test values ('004','tang');
SQL> insert into test values ('005','yan');
SQL> commit;
提交完成。
data_block_dump
===============
0xe:pti[0] nrow=5 offs=0 --增加了2條記錄
0x12:pri[0] offs=0xf93
0x14:pri[1] offs=0xf87
0x16:pri[2] offs=0xf7a
0x18:pri[3] offs=0xf6e --新增加的004號記錄
0x1a:pri[4] offs=0xf63 --新增加的005號記錄
block_row_dump:
tab 0, row 3, @0xf6e --第4條記錄開始地址
tl: 12 fb: --H-FL-- lb: 0x2 cc: 2
col 0: [ 3] 30 30 34 --字段1長度爲3,數據爲30 30 34
col 1: [ 4] 74 61 6e 67 --字段1長度爲4,數據爲74 61 6e 67
tab 0, row 4, @0xf63 --第5條記錄開始地址
tl: 11 fb: --H-FL-- lb: 0x2 cc: 2
col 0: [ 3] 30 30 35 --字段1長度爲3,數據爲30 30 35
col 1: [ 3] 79 61 6e --字段1長度爲3,數據爲79 61 6e
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 61574 maxblk 61574
2.刪除(delete)數據對數據塊的影響
刪除(delete):刪除數據時,oracle並不回收被刪除數據所佔用的空間,只是做一個標記以表明,這部分空間可以重用。如果一個數據塊因爲刪除了數據使得他的使用空間低於PCTUSED的值。那麼這個數據塊將被再次放到freelist中,當需要時就會被重用。一下是刪除一條數據以後數據塊中的變化:
SQL> delete from test where sno='002' or sno='003';
SQL> commit;
提交完成。
SQL> select * from test;
SNO SNAME
---------- --------------------
001 huang
004 tang
005 yan
SQL> exec show_space('TEST');
Total Blocks............................3
Total Bytes.............................12288
Unused Blocks...........................1
Unused Bytes............................4096
Last Used Ext FileId....................1
Last Used Ext BlockId...................61573
Last Used Block.........................2
PL/SQL 過程已成功完成。
SQL> alter system dump datafile 1 block 61574;
系統已更改。
block_row_dump:
tab 0, row 1, @0xf87 --原002的記錄位置,已經沒有數據
tl: 2 fb: --HDFL-- lb: 0x1
tab 0, row 2, @0xf7a --原003的記錄位置,已經沒有數據
tl: 2 fb: --HDFL-- lb: 0x1
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 61574 maxblk 61574
SQL> insert into test values ('002','t');
SQL> insert into test values ('003','g');
SQL> commit;
提交完成。
SQL> alter system dump datafile 1 block 61574;
系統已更改。
block_row_dump:
tab 0, row 1, @0xf87 --被刪除的002號記錄
tl: 2 fb: --HDFL-- lb: 0x1
tab 0, row 2, @0xf7a --被刪除的003號記錄
tl: 2 fb: --HDFL-- lb: 0x1
tab 0, row 5, @0xf5a --新增加的002號記錄
tl: 9 fb: --H-FL-- lb: 0x2 cc: 2
col 0: [ 3] 30 30 32 --新插入的002號記錄的數據
col 1: [ 1] 74
tab 0, row 6, @0xf51 --新增加的003號記錄
tl: 9 fb: --H-FL-- lb: 0x2 cc: 2
col 0: [ 3] 30 30 33 --新插入的003號記錄的數據
col 1: [ 1] 67
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 61574 maxblk 61574
3.更新(update)數據對數據塊的影響
更新(update):數據被更新時,oracle首先使用數據所在數據塊(block)所預留的空閒空間(PCTFREE)來存儲數據更新可能帶來的行數據增大。如果更新產生的新數據過大,造成數據塊(block)無法裝下新的數據,那麼將被拷貝到一個有足夠空間的數據塊中,而原始塊則會存儲一個指向更新夠新數據的開始地址。以下是更新兩條記錄以後數據塊的變化:
SQL> update test set sname='ting' where sno='002';
SQL> update test set sname='guang' where sno='003';
SQL> commit;
提交完成。
SQL> alter system dump datafile 1 block 61574;
系統已更改。
block_row_dump:
tab 0, row 5, @0xed6 --第5行記錄(新插入的002號記錄)
tl: 12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] 30 30 32
col 1: [ 4] 74 69 6e 67 --數據已經被更新
tab 0, row 6, @0xec9 --第6行記錄(新插入的003號記錄)
tl: 13 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] 30 30 33
col 1: [ 5] 67 75 61 6e 67 --數據已經被更新
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 61574 maxblk 61574
#####################################################
SHOW_SPACE是TOM寫的一個小工具,SHOW_SPACE實際上就是一個存儲過程,這個存儲過程可以用來分析空間按使用情況,十分的方便。以下爲SHOW_SPACE的腳本:
create or replace procedure show_space
( p_segname in varchar2,
p_owner in varchar2 default user,
p_type in varchar2 default 'TABLE',
p_partition in varchar2 default NULL )
as
l_total_blocks number;
l_total_bytes number;
l_unused_blocks number;
l_unused_bytes number;
l_LastUsedExtFileId number;
l_LastUsedExtBlockId number;
l_last_used_block number;
procedure p( p_label in varchar2, p_num in number )
is
begin
dbms_output.put_line( rpad(p_label,40,'.') || p_num );
end;
begin
dbms_space.unused_space
( segment_owner => p_owner,
segment_name => p_segname,
segment_type => p_type,
partition_name => p_partition,
total_blocks => l_total_blocks,
total_bytes => l_total_bytes,
unused_blocks => l_unused_blocks,
unused_bytes => l_unused_bytes,
last_used_extent_file_id => l_LastUsedExtFileId,
last_used_extent_block_id => l_LastUsedExtBlockId,
last_used_block => l_last_used_block );
p( 'Total Blocks', l_total_blocks );
p( 'Total Bytes', l_total_bytes );
p( 'Unused Blocks', l_unused_blocks );
p( 'Unused Bytes', l_unused_bytes );
p( 'Last Used Ext FileId', l_LastUsedExtFileId );
p( 'Last Used Ext BlockId', l_LastUsedExtBlockId );
p( 'Last Used Block', l_last_used_block );
end;
此工具的使用方法爲:
SQL> create table t as select * from all_users;
表已創建。
SQL> set serveroutput on;
SQL> exec show_space('T');
Total Blocks............................8
Total Bytes.............................65536
Unused Blocks...........................6
Unused Bytes............................49152
Last Used Ext FileId....................1
Last Used Ext BlockId...................60745
Last Used Block.........................2
PL/SQL 過程已成功完成。
不過此版本只適合表空間爲非ASSM的時候,當表空間爲ASSM時不能用,因爲DBMS_SPACE.FREE_BLOCKS不允許在ASSM上操作。要想在ASSM表空間的時候也能使用則可以使用以下版本:
create or replace procedure show_space
( p_segname_1 in varchar2,
p_space in varchar2 default 'MANUAL',
p_type_1 in varchar2 default 'TABLE' ,
p_analyzed in varchar2 default 'N',
p_owner_1 in varchar2 default user)
as
p_segname varchar2(100);
p_type varchar2(10);
p_owner varchar2(30);
l_unformatted_blocks number;
l_unformatted_bytes number;
l_fs1_blocks number;
l_fs1_bytes number;
l_fs2_blocks number;
l_fs2_bytes number;
l_fs3_blocks number;
l_fs3_bytes number;
l_fs4_blocks number;
l_fs4_bytes number;
l_full_blocks number;
l_full_bytes number;
l_free_blks number;
l_total_blocks number;
l_total_bytes number;
l_unused_blocks number;
l_unused_bytes number;
l_LastUsedExtFileId number;
l_LastUsedExtBlockId number;
l_LAST_USED_BLOCK number;
procedure p( p_label in varchar2, p_num in number )
is
begin
dbms_output.put_line( rpad(p_label,40,'.') ||
p_num );
end;
begin
p_segname := upper(p_segname_1);
p_owner := upper(p_owner_1);
p_type := p_type_1;
if (p_type_1 = 'i' or p_type_1 = 'I') then
p_type := 'INDEX';
end if;
if (p_type_1 = 't' or p_type_1 = 'T') then
p_type := 'TABLE';
end if;
if (p_type_1 = 'c' or p_type_1 = 'C') then
p_type := 'CLUSTER';
end if;
dbms_space.unused_space
( segment_owner => p_owner,
segment_name => p_segname,
segment_type => p_type,
total_blocks => l_total_blocks,
total_bytes => l_total_bytes,
unused_blocks => l_unused_blocks,
unused_bytes => l_unused_bytes,
LAST_USED_EXTENT_FILE_ID => l_LastUsedExtFileId,
LAST_USED_EXTENT_BLOCK_ID => l_LastUsedExtBlockId,
LAST_USED_BLOCK => l_LAST_USED_BLOCK );
if p_space = 'MANUAL' or (p_space <> 'auto' and p_space <> 'AUTO') then
dbms_space.free_blocks
( segment_owner => p_owner,
segment_name => p_segname,
segment_type => p_type,
freelist_group_id => 0,
free_blks => l_free_blks );
p( 'Free Blocks', l_free_blks );
end if;
p( 'Total Blocks', l_total_blocks );
p( 'Total Bytes', l_total_bytes );
p( 'Unused Blocks', l_unused_blocks );
p( 'Unused Bytes', l_unused_bytes );
p( 'Last Used Ext FileId', l_LastUsedExtFileId );
p( 'Last Used Ext BlockId', l_LastUsedExtBlockId );
p( 'Last Used Block', l_LAST_USED_BLOCK );
/*IF the segment is analyzed */
if p_analyzed = 'Y' then
dbms_space.space_usage(segment_owner => p_owner ,
segment_name => p_segname ,
segment_type => p_type ,
unformatted_blocks => l_unformatted_blocks ,
unformatted_bytes => l_unformatted_bytes,
fs1_blocks => l_fs1_blocks,
fs1_bytes => l_fs1_bytes ,
fs2_blocks => l_fs2_blocks,
fs2_bytes => l_fs2_bytes,
fs3_blocks => l_fs3_blocks ,
fs3_bytes => l_fs3_bytes,
fs4_blocks => l_fs4_blocks,
fs4_bytes => l_fs4_bytes,
full_blocks => l_full_blocks,
full_bytes => l_full_bytes);
dbms_output.put_line(rpad(' ',50,'*'));
dbms_output.put_line('The segment is analyzed');
p( '0% -- 25% free space blocks', l_fs1_blocks);
p( '0% -- 25% free space bytes', l_fs1_bytes);
p( '25% -- 50% free space blocks', l_fs2_blocks);
p( '25% -- 50% free space bytes', l_fs2_bytes);
p( '50% -- 75% free space blocks', l_fs3_blocks);
p( '50% -- 75% free space bytes', l_fs3_bytes);
p( '75% -- 100% free space blocks', l_fs4_blocks);
p( '75% -- 100% free space bytes', l_fs4_bytes);
p( 'Unused Blocks', l_unformatted_blocks );
p( 'Unused Bytes', l_unformatted_bytes );
p( 'Total Blocks', l_full_blocks);
p( 'Total bytes', l_full_bytes);
end if;
end;
以下是此版本的SHOW_SPACE的使用方法簡介:
ASSM 類型的表
SQL> exec show_space('t','auto');
Total Blocks............................512
Total Bytes.............................4194304
Unused Blocks...........................78
Unused Bytes............................638976
Last Used Ext FileId....................9
Last Used Ext BlockId...................25608
Last Used Block.........................50
PL/SQL procedure successfully completed.
ASSM 類型的索引
SQL> exec show_space('t_index','auto','i');
Total Blocks............................80
Total Bytes.............................655360
Unused Blocks...........................5
Unused Bytes............................40960
Last Used Ext FileId....................9
Last Used Ext BlockId...................25312
Last Used Block.........................3
PL/SQL procedure successfully completed.
對analyze 過的segment 可以這樣
SQL> exec show_space('t','auto','T','Y');
Total Blocks............................512
Total Bytes.............................4194304
Unused Blocks...........................78
Unused Bytes............................638976
Last Used Ext FileId....................9
Last Used Ext BlockId...................25608
Last Used Block.........................50
*************************************************
The segment is analyzed
0% -- 25% free space blocks.............0
0% -- 25% free space bytes..............0
25% -- 50% free space blocks............0
25% -- 50% free space bytes.............0
50% -- 75% free space blocks............0
50% -- 75% free space bytes.............0
75% -- 100% free space blocks...........0
75% -- 100% free space bytes............0
Unused Blocks...........................0
Unused Bytes............................0
Total Blocks............................418
Total bytes.............................3424256
PL/SQL procedure successfully completed