SQL> alter system dump datafile 5 block 3;
System altered.
查看DUMP文件,有如下信息
Start dump data blocks tsn: 5 file#: 5 minblk 3 maxblk 3
buffer tsn: 5 rdba: 0x01400003 (5/3)
scn: 0x0000.202f7a6f seq: 0x01 flg: 0x00 tail: 0x7a6f1e01
frmt: 0x02 chkval: 0x0000 type: 0x1e=KTFB Bitmapped File Space Bitmap
File Space Bitmap Block:
BitMap Control:
RelFno: 5, BeginBlock: 9, Flag: 0, First: 16, Free: 63472
FFFF000000000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
.....
注意其中的FFFF00,,這是16進制的表現方法,我們轉換爲二進制,有
1111,1111,1111,1111,0000,0000
發現這裏有16個1,每一個1就是一個位(bit),代表64K,也就代表了該表空間有已經分配了的16個extent,如果我們將該表擴展,將又有什麼結果呢?
SQL> alter table demotab allocate extent;
Table altered.
SQL> alter table demotab allocate extent;
Table altered.
SQL> alter table demotab allocate extent;
Table altered.
這樣之後,我們應該有19個extent了,再dump第三個塊
Start dump data blocks tsn: 5 file#: 5 minblk 3 maxblk 3
buffer tsn: 5 rdba: 0x01400003 (5/3)
scn: 0x0000.202f7c64 seq: 0x01 flg: 0x00 tail: 0x7c641e01
frmt: 0x02 chkval: 0x0000 type: 0x1e=KTFB Bitmapped File Space Bitmap
File Space Bitmap Block:
BitMap Control:
RelFno: 5, BeginBlock: 9, Flag: 0, First: 19, Free: 63469
FFFF07 0000000000 0000000000000000 0000000000000000 0000000000000000
除了以前的FFFF,現在多了07,怎麼解釋呢?
07轉換爲二進制爲0000,0111,但是還是不夠解釋以上的情況,這裏我們沒有考慮到字節交換的情況,因爲以上FF交換後還是FF,但是如果是07,我們就必須考慮字節交換(因爲計算機是一個字節一個字節的寫,一個字節佔兩位當然是先寫後面了,如從01到0F到FF爲止。 如果我們明白了,那麼FFFF07轉換爲二進制爲 1111,1111,1111,1111,0000,0111。
每個字節交換得
1111,1111,1111,1111,1110,0000
可以發現,這裏有19個1,也就是19個位(bit),代表了現在的19個extent。
5、 同樣我們dump該數據文件第9個塊,則有
Start dump data blocks tsn: 5 file#: 5 minblk 9 maxblk 9
buffer tsn: 5 rdba: 0x01400003 (5/3)
scn: 0x0000.202f7c64 seq: 0x01 flg: 0x00 tail: 0x7c641e01
frmt: 0x02 chkval: 0x0000 type: 0x1e=KTFB Bitmapped File Space Bitmap
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0 space2: 0 #extents: 16 #blocks: 127
last map 0x00000000 #maps: 0 offset: 4128
Highwater:: 0x01c0000a ext#: 0 blk#: 0 ext size: 7
#blocks in seg. hdr's freelists: 0
#blocks below: 0
mapblk 0x00000000 offset: 0
Disk Lock:: Locked by scn: 0x0006.012.00000017
Map Header:: next 0x00000000 #extents: 16 obj#: 3090 flag: 0x40000000
Extent Map
-----------------------------------------------------------------
0x01c0000a length: 7
0x01c00011 length: 8
0x01c00019 length: 8
0x01c00021 length: 8
0x01c00029 length: 8
0x01c00031 length: 8
0x01c00039 length: 8
0x01c00041 length: 8
0x01c00049 length: 8
0x01c00051 length: 8
0x01c00059 length: 8
0x01c00061 length: 8
0x01c00069 length: 8
0x01c00071 length: 8
0x01c00079 length: 8
0x01c00081 length: 8
nfl = 1, nfb = 1 typ = 1 nxf = 0
SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 End dump data blocks tsn: 5 file#: 5 minblk 9 maxblk 9
這是該數據文件中表DEMOTAB的表頭(一個塊)信息, 從這裏可以看到,該表從第9個塊開始使用Highwater:: 0x01c0000a已經是第10個塊了,從以上列表,我們也能清楚的看到,該表耗費了16個區間。
由於該表是數據文件的第一個表,所以位圖區佔用從3到8共6個塊,加上前面兩個文件頭,也就是說,在數據文件頭部共8個塊用於系統消耗。如果我們的db_block_size爲8192,那麼很明顯,佔用的空間爲64K(注意:對於不同的塊大小,文件頭部的塊個數與大小可能會不一樣)。也因爲僅僅操作數據文件頭部幾個塊,不用操作數據字典,所以ORACLE在本地管理的表空間中添加,刪除段的時候,效率要比字典管理的表空間快。特別是在併發性很強的空間請求中。
ORACLE通過強制性的手段使本地管理表空間中的所有Extent是同樣大小的,儘管你可能自定義了不同的存儲參數。
6、 補充一些字典管理表空間的不同
a. 如果是字典管理,表空間中的表的區間的大小取決於表的存儲參數,如果沒有定義,則取表空間的通用存儲參數。所以每個表的區間大小可以不一樣。
b. 如果不指定表的最少區間數,那麼默認創建的時候,該表只有一個區間,而不是多個區間。
c. 字典管理的文件頭只佔用一個塊,第一個表的HWM應當是Highwater:: x01c00003,關於這個可以自己dump該數據文件查看。
Autoallocate的本地管理表空間在自動分配的本地管理的表空間中,區間尺寸可能由以下尺寸組成64k, 1m, 8m, 64m 甚至是256m。但是不管多大,都有一個通用尺寸64k,所
以64K就是該表空間的位大小。
SQL> create tablespace dummy
datafile 'c:\dummy01.dbf' size 100m
autoallocate;
Tablespace created.
SQL> create table x1 (x number)
tablespace dummy
storage (initial 50M);
Table created.
SQL> select file# from v$datafile where name like '%DUMMY%';
FILE#
----------
12
SQL> select extents from user_segments
where segment_name = 'X1' ;
EXTENTS
----------
50
SQL> alter system dump datafile 12 block 3;
System altered.
*** SESSION ID11.59) 2002-11-22 10:37:35.000
Start dump data blocks tsn: 19 file#: 12 minblk 3 maxblk 3
buffer tsn: 19 rdba: 0x03000003 (12/3)
scn: 0x0000.00f2959b seq: 0x01 flg: 0x00 tail: 0x959b1e01
frmt: 0x02 chkval: 0x0000 type: 0x1e=KTFB Bitmapped File Space Bitmap
File Space Bitmap Block:
BitMap Control:
RelFno: 12, BeginBlock: 9, Flag: 0, First: 800, Free: 62688
FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF
FFFFFFFF00000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
可以看到該表實際只有50個區間(extent),但是有800個位(bit)
50*1024=800*64
還可以看出,位大小並不等於extent大小。
五、遷移到本地管理表空間
在很多情況下,如果你想在字典表空間與本地表空間之間轉換是很難的,你可能需要轉出該表空間所有的數據,從新創建表空間,再加載該數據。但是在816以後,有一個叫dbms_space_admin的包使兩類表空間的互相轉換變成可能,體現在如下兩個過程:
DBMS_SPACE_ADMIN.TABLESPACE_MIGRATE_TO_LOCAL
DBMS_SPACE_ADMIN.TABLESPACE_MIGRATE_FROM_LOCAL
但是在你想利用這個過程進行轉換的時候,你必須注意兩件事:
1、 數據庫版本必須是816以上,兼容版本(compatible)必須是8.1以上
2、 如果是轉換成爲本地管理,必須有足夠的空閒空間做本地位圖空間(8個塊)
當從字典管理到本地管理的過程中,全部轉換其實基本上是不可能發生的,實際情況是,對於已經存在的數據和空間,該過程是沒有任何辦法的,僅僅是簡單把空間取整並標記。所以說,這種轉換後的表空間可以減緩UET$和FET$的壓力,但並不能解決碎片問題。從查詢DBA_TABLESPACES你還可以看到,轉換之後的表空間管理方式是LOCAL,但實際段分配是USER(不是uniform或automatic)。
很顯然,在字典管理的表空間中,存在許多大小不同的區間(extent)尺寸,所以轉換爲本地管理的時候,ORACLE怎麼樣把這些已經存在的空間轉換爲通用大小了?爲了做到這一點,ORACLE必須掃描該表空間的每個數據文件,主要是檢查以下三個問題:
1、 所有的已經存在的區間
2、 所有的以前用過,但是現在空閒的空間
3、 由表空間MINIMUM EXTENT語句標記的大小
在轉換的時候,ORACLE試圖發現一個適合於以上三個標準的最大的區間的尺寸作爲本地管理的區間尺寸,也就是說,在最壞的情況下,這個最大的區間可能就是單個塊(如果說一個表的區間尺寸是7個塊,另外一個表的區間尺寸是8個塊)
我們看一個從字典管理表空間到本地管理表空間的例子
1、首先,我們創建一個字典管理表空間
SQL> create tablespace blah
datafile 'G:\ORA9I\ORADATA\DB9\BLAH.DBF' size 10m reuse
extent management dictionary;
Tablespace altered.
SQL> col bytes format 999,999,999
SQL> select * from dba_free_space where tablespace_name = 'BLAH';
TABLESPACE_NAME FILE_ID BLOCK_ID BYTES BLOCK RELATIVE_FNO
--------------- -------- ----------- ------------ ------- ----------------
BLAH 8 2 10,477,568 1279 8
2、我們在上面創建三個表,最小公用尺寸是400K
SQL> create table t1 ( x number ) storage ( initial 400k) tablespace blah;
Table created.
SQL> create table t2 ( x number ) storage ( initial 800k) tablespace blah;
Table created.
SQL> create table t3 ( x number ) storage ( initial 1200k) tablespace blah;
Table created.
SQL> select * from dba_free_space where tablespace_name = 'BLAH';
TABLESPACE_NAME FILE_ID BLOCK_ID BYTES BLOCK RELATIVE_FNO
--------------- -------- ----------- ----------- ------- ----------------
BLAH 8 302 8,019,968 979 8
SQL> select bytes from dba_extents where tablespace_name = 'BLAH';
BYTES
----------
409,600
819,200
1,228,800
3、現在我們開始轉換該表空間爲本地管理的表空間,假定每個位圖大小400K,也就是50個塊。
SQL> exec dbms_space_admin.TABLESPACE_MIGRATE_TO_LOCAL('BLAH',50);
BEGIN dbms_space_admin.TABLESPACE_MIGRATE_TO_LOCAL('BLAH',50); END;
*
ERROR at line 1:
ORA-03241: Invalid unit size
ORA-06512: at "SYS.DBMS_SPACE_ADMIN", line 0
ORA-06512: at line 1
如果我們設置表空間的minimum extent語句爲400K:
SQL> alter tablespace blah minimum extent 400k;
Tablespace altered.
SQL> exec dbms_space_admin.TABLESPACE_MIGRATE_TO_LOCAL('BLAH',50);
PL/SQL procedure successfully completed.
Conversion goes through with no problems.
從以上可以看到,轉換成功,但實際情況遠遠比這麼複雜,或許你根本就不知道表空間裏面的公用尺寸是多大。而且通過這種轉換後的表空間,並沒有消除碎片,也不一定有優化的作用。所以建議不要用該方法進行轉換,而是使用alter table move的辦法進行表空間的轉換將可能是最好的辦法。