Oracle 本地表空間管理與字典表空間管理

hd_system發表於2016-11-15
本地管理表空間
一、概述
1、理解本地管理表空間的由來
2、理解什麼是字典管理表空間及工作原理
3、理解本地管理表空間的優勢(為什麼要使用本地管理表空間)
4、理解本地管理表空間的內部結構
5、理解字典管理表空間與本地管理表空間的轉換
二、名詞解釋與約定
表空間(Tablespace)——為資料庫提供使用空間的邏輯結構,其對應物理結構是資料檔案,一個表空間可以包含多個資料檔案。
本地管理表空間(Locally Managed Tablespace簡稱LMT)——8i以後出現的一種新的表空間的管理模式,透過本地點陣圖來管理表空間的空間使

用。
字典管理表空間(Dictionary-Managed Tablespace簡稱DMT)——8i以前包括以後都還可以使用的一種表空間管理模式,透過資料字典管理表

空間的空間使用。
段(Segment)——資料庫一種邏輯結構,如表段,索引段,回滾段等,段存在於表空間中,並對應一定的儲存空間。
區間,可以簡稱區(Extent)——段的儲存可以分成一個或多個區間,每個區間佔用一定數量的資料塊(block),在本地管理的表空間中,表

空間的Extent就對應段的Extent。
塊(Block)——資料庫最小的儲存單位,在本文中Block的大小約定為8192位元組。
位(Bit)——本地管理表空間的空間管理單位,一個位可能等於一個區間,也可能多個位組成一個區間。
三、本地管理表空間的由來
在Oracle8I的版本中,Oracle推出了一種全新的表空間管理方式:本地化管理的表空間。所謂本地化管理,就是指Oracle不再利用資料字典表

來記錄Oracle表空間裡面的區的使用狀況,而是在每個表空間的資料檔案的頭部加入了一個點陣圖區,在其中記錄每個區的使用狀況。每當一個

區被使用,或者被釋放以供重新使用時,Oracle都會更新資料檔案頭部的這個記錄,反映這個變化。本地化管理的表空間的建立過程:
語法:CREATE TABLESPACE 表空間名字
          DATAFILE '資料檔案詳細資訊'
          [EXTENT MANAGEMENT { LOCAL
          {AUTOALLOCATE | UNIFORM [SIZE INTETER [K|M] ] } } ]

關鍵字EXTENT MANAGEMENT LOCAL 指定這是一個本地化管理的表空間。對於系統表空間,只能在建立資料庫的時候指定EXTENT MANGEMENT 

LOCAL,因為它是資料庫建立時建立的第一個表空間。
在8i中,字典管理還是預設的管理方式,當選擇了LOCAL關鍵字,即表明這是一個本地管理的表空間。當然還可以繼續選擇更細的管理方式:是

AUTOALLOCATE 還是 UNIFORM.。若為AUTOALLOCATE,則表明讓Oracle來決定區塊的使用辦法;若選擇了UNIFORM,則還可以詳細指定每個區塊的

大小,若不加指定,則為每個區使用1M大小。
Oracle之所以推出了這種新的表空間管理方法,讓我們來看一下這種表空間組織方法的優點:
1. 本地化管理的表空間避免了遞迴的空間管理操作。而這種情況在資料字典管理的表空間是經常出現的,當表空間裡的區的使用狀況發生改變

時,資料字典的表的資訊發生改變,從而同時也使用了在系統表空間裡的回滾段。
2. 本地化管理的表空間避免了在資料字典相應表裡面寫入空閒空間、已使用空間的資訊,從而減少了資料字典表的競爭,提高了空間管理的並

發性。
3. 區的本地化管理自動跟蹤表空間裡的空閒塊,減少了手工合併自由空間的需要。
4. 表空間裡的區的大小可以選擇由Oracle系統來決定,或者由資料庫管理員指定一個統一的大小,避免了字典表空間一直頭疼的碎片問題。
5. 從由資料字典來管理空閒塊改為由資料檔案的頭部記錄來管理空閒塊,這樣避免產生回滾資訊,不再使用系統表空間裡的回滾段。因為由數

據字典來管理的話,它會把相關資訊記在資料字典的表裡,從而產生回滾資訊。
由於這種表空間的以上特性,所以它支援在一個表空間裡邊進行更多的併發操作,並減少了對資料字典的依賴。
四、本地管理表空間管理機制
表空間是一種為段(表,索引等)提供空間的邏輯結構,所以,當在表空間中增加,刪除段的時候,資料庫就必須跟蹤這些空間的使用。
如下例所示,假定一個新建立的表空間包含了五個表
表一……表二……表三……表四……表五……未用空間
當我們刪除表四的時候,就有如下結果
表一……表二……表三……空閒空間段……表五……未用空間
很明顯,ORACLE需要有一個機制來管理表空間中各資料檔案的這些分配的或未分配的空間,為了跟蹤這些可以使用的空間(包括未分配使用的

和可以重複使用的),對於每一個空間,我們必須知道:
1、這個可用空間位於什麼資料檔案
2、這個空間的尺寸是多大
3、如果它在用了,是哪一個段佔用的這個空間
直到8i之前,所有的表空間都是採用字典管理模式,為了確保能儲存以上的資訊,ORACLE用了兩個資料字典表:UET$(已使用的區間)或FET$(

空閒空間):
SQL> desc UET$
Name Null? Type
----------------- ----------- -----------
SEGFILE# NOT NULL NUMBER
SEGBLOCK# NOT NULL NUMBER | The segment that uses this space
EXT# NOT NULL NUMBER
TS# NOT NULL NUMBER | The tablespace ID and the file
FILE# NOT NULL NUMBER | ID for that tablespace
BLOCK# NOT NULL NUMBER
LENGTH NOT NULL NUMBER | The location and size of the chunk

SQL> desc FET$
Name Null? Type
----------------- ----------- -----------
TS# NOT NULL NUMBER | The tablespace ID and the file
FILE# NOT NULL NUMBER | ID for that tablespace
BLOCK# NOT NULL NUMBER
LENGTH NOT NULL NUMBER | The location and size of the chunk
查詢該表可以看到,每個使用空間或空閒空間(不一定是一個extent,可以是多個extent)都在該表中對應了一行。它的工作方式是當一個段

被刪除的時候,ORACLE就移動UET$中相應的行到FET$,這個過程的發生是連續的,而且可能發生等待。當併發性很高的時候,資料字典的爭用

就來了。另外有一個問題就是,當表的空間很不連續或表空間有大量的碎片引起這兩個表的增大,那麼也就會引起資料庫效能上的下降。
本地管理表空間正是為了解決這一問題來的,在表空間的空間管理上,ORACLE將儲存資訊儲存在表空間的頭部的點陣圖中,而不是儲存在資料字

典中。透過這樣的方式,在分配回收空間的時候,表空間就可以獨立的完成操作也不用與其它物件關係。
下面就讓我們進入到本地管理表空間的內部,看看ORACLE是怎麼實現這一工作的。
Uniform方式的本地管理表空間
1、 先建立了一個本地管理的表空間,區間統一大小分配為64K
SQL> create tablespace demo
datafile '/ora01/oem/oemdemo01.dbf' size 10m
extent management local uniform size 64k;
2、 在該表空間中建立一個表
SQL>create table demotab ( x number ) tablespace demo
storage ( initial 1000K next 1000k );
我們透過查詢該表
SQL> select t.table_name,t.initial_extent,t.next_extent from user_tables t where t.table_name = 'DEMOTAB';
TABLE_NAME INITIAL_EXTENT NEXT_EXTENT
------------------------------ -------------- -----------
DEMOTAB 1024000 65536
可以發現,該表的儲存引數並不是我們指定的引數INITIAL_EXTENT,而是uniform size的整數倍,NEXT_EXTENT則等於uniform size。我們從該

查詢就也可以看到如下情況
SQL>select count(*) from user_extents where segment_name = 'DEMOTAB';
COUNT(*)
----------
16
也就是說,該表在該表空間中已經存在16個extent,而不是一個extent(這是與字典管理的差別,如果是字典管理的表空間,如果建立以上的

表,該查詢的結果是1)。
3、 獲取該資料檔案的檔案ID
SQL> col name format a30 trunc
SQL> select file#, name from v$datafile;
File# NAME
----- --------------------
1 /oras1/oem/oemsystem01.dbf
2 /oras3/oem/oemundo01.dbf
3 /ora01/oem/oemoem_repository01
4 /ora01/oem/oemrcat01.dbf
5 /ora01/oem/oemdemo01.dbf
我們可以檢查uet$與fet$
SQL> select count(*) from uet$ where file# = 5;
COUNT(*)
----------
0
SQL> select count(*) from fet$ where file# = 5;
COUNT(*)
----------
0 4、 可以看到,ORACLE沒有在這兩個表中儲存任何資訊,現在我們dump該資料檔案的第三個塊。
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的辦法進行表空間的轉換將可能是最好的辦法。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29209863/viewspace-2128512/,如需轉載,請註明出處,否則將追究法律責任。

相關文章