hwm的一點理解

zzy020128發表於2011-03-30

[@more@]

ASSM(auto segment space management )首次出現在Oracle920裡,連結列表freelist被點陣圖所取代,它是一個二進位制的陣列,能夠迅速有效地管理儲存擴充套件和剩餘區塊(free block),因此能夠改善分段儲存本質,ASSM表空間上建立的段還有另外一個稱呼叫Bitmap Managed Segments(BMB 段)。assm忽略了pctused 和freelist等,但卻沒有忽略pctfree引數。PCTFREE是指預留多少空間給後面更新,如果一個表的更新非常頻繁,則可以考慮把pctfree設定得大一點,這樣能減少行遷移,但是過大則會浪費空間和低的塊密度。

HWM(hwd high water mark)
高水位, 表中資料使用的空間的最高的位置, 就如同水壩的高水位的概念, 表明用到的最大的空間的位置, 目前可能由於資料的刪除, 並不是所有的空間都儲存有資料. 就如同水壩不是什麼時候水位都是在最高點一樣.

--------------------------檢視錶空間的段空間模式-------------------------------------

在oracle10.1.0.2.0版本中,建立表空間,預設的段空間管理為本地管理的手工管理模式,而在
oracle10.2.0.1.0中是assm模式,即本地管理的自動管理模式

SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for Linux: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production

SQL> create tablespace a datafile 'a01.dbf' size 10m;

Tablespace created.

SQL> select tablespace_name , segment_space_management from dba_tablespaces;

tablespace_name segment_space_management
------------------------------ ------
... ...
A AUTO


segment_space_management為auto則表示是assm模式,為manual表示為手工模式

---------------------------------------------檢視hmw---------------------------------------

--編譯過程:
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); -- rainy changed
p_owner := upper(p_owner_1);
p_type := p_type_1;

if (p_type_1 = 'i' or p_type_1 = 'I') then
--rainy changed
p_type := 'INDEX';
end if;

if (p_type_1 = 't' or p_type_1 = 'T') then
--rainy changed
p_type := 'TABLE';
end if;

if (p_type_1 = 'c' or p_type_1 = 'C') then
--rainy changed
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 ;

/
--然後執行即可
SQL> set serverout on;
SQL> exec show_space('test','auto'); ---auto表示assm模式

Total Blocks............................26496
Total Bytes.............................217055232
Unused Blocks...........................958
Unused Bytes............................7847936
Last Used Ext FileId....................5
Last Used Ext BlockId...................1438481
Last Used Block.........................66

PL/SQL procedure successfully completed

使用塊數為 Total Blocks - Unused Blocks = 26496 - 958 = 25538
HWM的位置為Total Blocks - Last Used Block. = 1438481 + 66 - 1= 1438546
在oracle10g中可以使用如下指令碼聯機來處理hwm

alter table test enable row movement;
alter table test shrink space;

----------以下是對hwm的詳細介紹---------

說到HWM,我們首先要簡要的談談ORACLE的邏輯儲存管理.我們知道,ORACLE在邏輯儲存上分4個粒度:表空間,段,區和塊.

(1)塊:是粒度最小的儲存單位,現在標準的塊大小是8K,ORACLE每一次I/O操作也是按塊來操作的,也就是說當ORACLE從資料檔案讀資料時,是讀取多少個塊,而不是多少行.

(2)區:由一系列相鄰的塊而組成,這也是ORACLE空間分配的基本單位,舉個例子來說,當我們建立一個表PM_USER時,首先ORACLE會分配一區的空間給這個表,隨著不斷的INSERT資料到PM_USER,原來的這個區容不下插入的資料時,ORACLE是以區為單位進行擴充套件的,也就是說再分配多少個區給PM_USER,而不是多少個塊.

(3)段:是由一系列的區所組成,一般來說,當建立一個物件時(表,索引),就會分配一個段給這個物件.所以從某種意義上來說,段就是某種特定的資料.如CREATE TABLE PM_USER,這個段就是資料段,而CREATE INDEX ON PM_USER(NAME),ORACLE同樣會分配一個段給這個索引,但這是一個索引段了.查詢段的資訊可以通過資料字典: SELECT * FROM USER_SEGMENTS來獲得,

(4)表空間:包含段,區及塊.表空間的資料物理上儲存在其所在的資料檔案中.一個資料庫至少要有一個表空間.

現在回到HWM上來,那麼,什麼是高水位標記呢?這就跟ORACLE的段空間管理相關了.


(一)ORACLE用HWM來界定一個段中使用的塊和未使用的塊.
舉個例子來說,當我們建立一個表:PT_SCHE_DETAIL時,ORACLE就會為這個物件分配一個段.在這個段中,即使我們未插入任何記錄,也至少有一個區被分配,第一個區的第一個塊就稱為段頭(SEGMENT HEADE),段頭中就儲存了一些資訊,基中HWM的資訊就儲存在此.此時,因為第一個區的第一塊用於儲存段頭的一些資訊,雖然沒有儲存任何實際的記錄,但也算是被使用,此時HWM是位於第2個塊.當我們不斷插入資料到PM_USER後,第1個塊已經放不下後面新插入的資料,此時,ORACLE將高水位之上的塊用於儲存新增資料,同時,HWM本身也向上移.也就是說,當我們不斷插入資料時,HWM會往不斷上移,這樣,在HWM之下的,就表示使用過的塊,HWM之上的就表示已分配但從未使用過的塊.

(二)HWM在插入資料時,當現有空間不足而進行空間的擴充套件時會向上移,但刪除資料時不會往下移.
這就好比是水庫的水位,當漲水時,水位往上移,當水退出後,最高水位的痕跡還是清淅可見.
考慮讓我們看一個段,如一張表,其中填滿了塊。在正常操作過程中,刪除了一些。現有就有了許多浪費的空間:(I) 在表的上一個末端和現有的塊之間,以及 (II) 在塊內部,其中還有一些沒有刪除的行。
ORACLE 不會釋放空間以供其他物件使用,有一條簡單的理由:由於空間是為新插入的行保留的,並且要適應現有行的增長。被佔用的最高空間稱為最高使用標記 (HWM),

(三)HWM的資訊儲存在段頭當中.
HWM本身的資訊是儲存在段頭.在段空間是手工管理方式時,ORACLE是通過FREELIST(一個單向連結串列)來管理段內的空間分配.在段空間是自動管理方式時(ASSM),ORACLE是通過BITMAP來管理段內的空間分配.

(四)ORACLE的全表掃描是讀取高水位標記(HWM)以下的所有塊.
所以問題就產生了(一直不解為何ORACLE會採用這種不合理的方式).當使用者發出一個全表掃描時,ORACLE 始終必須從段一直掃描到 HWM,即使它什麼也沒有發現。該任務延長了全表掃描的時間。

(五)當用直接路徑插入行時 — 例如,通過直接載入插入(用 APPEND 提示插入)或通過 SQL*LOADER 直接路徑 — 資料塊直接置於 HWM 之上。它下面的空間就浪費掉了。

我們來分析這兩個問題,後者只是帶來空間的浪費,但前者不僅是空間的浪費,而且會帶來嚴重的效能問題.我們來看看下面的例子:

(A)我們先來搭建測試的環境,第一步先建立一個段空間為手工管理的表空間:

CREATE TABLESPACE "RAINNY"
LOGGING
DATAFILE 'D:ORACLE_HOMEORADATARAINNYRAINNY.ORA' SIZE 5M
AUTOEXTEND
ON NEXT 10M MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL
SEGMENT SPACE MANAGEMENT MANUAL;

B)建立一個表,注意,此表的第二個欄位我故意設成是CHAR(100),以讓此表在插入1千萬條記錄後,空間有足夠大:

CREATE TABLE TEST_TAB(C1 NUMBER(10),C2 CHAR(100)) TABLESPACE RAINNY;

插入記錄
DECLARE
I NUMBER(10);
BEGIN
FOR I IN 1..10000000 LOOP
INSERT INTO TEST_TAB VALUES(I,'TESTSTRING');
END LOOP;
COMMIT;
END ;

(C)我們來查詢一下,看在插入一千萬條記錄後所訪問的塊數和查詢所用時間:

SQL> SET TIMING ON
SQL> SET AUTOTRACE TRACEONLY
SQL> SELECT COUNT(*) FROM TEST_TAB;


ELAPSED: 00:01:03.05
EXECUTION PLAN
----------------------------------------------------------

0 SELECT STATEMENT PTIMIZER=CHOOSE (COST=15056 CARD=1)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'TEST_TAB' (COST=15056 CARD=10000000)

STATISTICS
----------------------------------------------------------
0 RECURSIVE CALLS
0 DB BLOCK GETS
156310 CONSISTENT GETS
154239 PHYSICAL READS
0 REDO SIZE
379 BYTES SENT VIA SQL*NET TO CLIENT
503 BYTES RECEIVED VIA SQL*NET FROM CLIENT
2 SQL*NET ROUNDTRIPS TO/FROM CLIENT
0 SORTS (MEMORY)
0 SORTS (DISK)
1 ROWS PROCESSED


我們來看上面的執行計劃,這句SQL總供耗時是:1分3秒.訪問方式是採用全表掃描方式(FTS),邏輯讀了156310個BLOCK,物理讀了154239個BLOCK.


我們來分析一下這個表:

BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=> 'TEST',
TABNAME=> 'TEST_TAB',
PARTNAME=> NULL);
END;

發現這個表目前使用的BLOCK有: 156532,未使用的BLOCK(EMPTY_BLOCKS)為:0,總行數為(NUM_ROWS):1000 0000

(D)接下來我們把此表的記錄用DELETE方式刪掉,然後再來看看SELECT COUNT(*) FROM TEST_TAB所花的時間:

DELETE FROM TEST_TAB;
COMMIT;

SQL> SELECT COUNT(*) FROM TEST_TAB;

ELAPSED: 00:01:04.03
EXECUTION PLAN
----------------------------------------------------------
0 SELECT STATEMENT PTIMIZER=CHOOSE (COST=15056 CARD=1)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'TEST_TAB' (COST=15056 CARD=1)
STATISTICS
----------------------------------------------------------
0 RECURSIVE CALLS
0 DB BLOCK GETS
156310 CONSISTENT GETS
155565 PHYSICAL READS
0 REDO SIZE
378 BYTES SENT VIA SQL*NET TO CLIENT
503 BYTES RECEIVED VIA SQL*NET FROM CLIENT
2 SQL*NET ROUNDTRIPS TO/FROM CLIENT
0 SORTS (MEMORY)
0 SORTS (DISK)
1 ROWS PROCESSED

在DELETE表後,此時表中已沒有一條記錄,為什麼SELECT COUNT(*) FROM TEST_TAB花的時間為1分4秒,反而比有記錄稍微長點,這是為什麼呢?而且其邏輯讀了156310個 BLOCK,跟之前有一千萬行記錄時差不多,ORACLE怎麼會這麼笨啊?
在DELETE表後再次分析表,看看有什麼變化:

這時, TEST_TAB表目前使用的BLOCK是: 156532,未使用的BLOCK(EMPTY_BLOCKS)為:0,總行數為(NUM_ROWS)已變成:0
為什麼表目前使的BLOCK數還是156532呢?

問題的根源就在於ORACLE的HWM.也就是說,在新增記錄時,HWM會慢慢往上移,但是在刪除記錄後,HWM卻不會往下移,也就是說,DELETE一千萬條記錄後,此表的HWM根本沒移動,還在原來的那個位置,所以,HWM以下的塊數同樣也是一樣的.ORACLE的全表掃描是讀取ORACLE高水位標記下的所有BLOCK,也就是說,不管HWM下的BLOCK現在實際有沒有存放資料,ORACLE都會一一讀取,這樣,大家可想而知,在我們DELETE表後,ORACLE讀了大量的空塊,耗去了大量的時間.


我們再來看DELETE表後段空間實際使用的狀況:

SQL> EXEC SHOW_SPACE('TEST_TAB','TEST');

TOTAL BLOCKS............................164352 --總共164352塊
TOTAL BYTES.............................1346371584
UNUSED BLOCKS...........................7168 --有7168塊沒有用過,也就是在HWM上面的塊數
UNUSED BYTES............................58720256
LAST USED EXT FILEID....................9
LAST USED EXT BLOCKID...................158856--- BLOCK ID 是針對資料檔案來編號的,表示最後使用的一個EXTENT的第一個BLOCK的編號
LAST USED BLOCK.........................1024 在最後使用的一個EXTENT 中一共用了1024塊

總共用了164352塊,除了一個SEGMENT HEADER,實際總共用了164351個塊,有7168塊從來沒有使用過。LAST USED BLOCK表示在最後一個使用的EXTENT 中使用的BLOCK, 結合 LAST USED EXT BLOCK ID可以計算 HWM 位置 :
LAST USED EXT BLOCK ID + LAST USED BLOCK -1 = HWM 所在的資料檔案的BLOCK編號

代入得出: 158856+1024-1=159879,這個就是HWM所有的BLOCK編號
HWM所在的塊:TOTAL BLOCKS- UNUSED BLOCKS=164352-7168=157184,也就是說,HWM在第157184個塊,其BLOCKID是159879


(E)結下來,我們再做幾個試驗:

第一步:執行ALTER TABLE TEST_TAB DEALLOCATE UNUSED;
用來分配UNUSED BLOCKS的資源
我們看看段空間的使用狀況:

SQL> EXEC SHOW_SPACE('TEST_TAB','TEST');
TOTAL BLOCKS............................157184
TOTAL BYTES.............................1287651328

UNUSED BLOCKS...........................0
UNUSED BYTES............................0
LAST USED EXT FILEID....................9
LAST USED EXT BLOCKID...................158856
LAST USED BLOCK.........................1024

此時我們再代入上面的公式,算出HWM的位置: 157184-0=157184 HWM所在的BLOCK ID是158856+1024-1=159879,跟剛剛的沒有變化,也就是說執行ALTER TABLE TEST_TAB DEALLOCATE UNUSED後,段的高水位標記的位置沒有改變,但是大家看看UNUSED BLOCKS變為0了,總的塊數減少到157184,這證明,DEALLOCATE UNUSED為釋放HWM上面的未使用空間,但是並不會釋放HWM下面的自由空間,也不會移動HWM的位置.


第二步:我們再來看看執行ALTER TABLE TEST_TAB MOVE後段空間的使用狀況:
SQL> EXEC SHOW_SPACE('TEST_TAB','TEST');
TOTAL BLOCKS............................8
TOTAL BYTES.............................65536
UNUSED BLOCKS...........................5
UNUSED BYTES............................40960
LAST USED EXT FILEID....................9
LAST USED EXT BLOCKID...................2632
LAST USED BLOCK.........................3


此時,總共用到的塊數已變為8, 我們再代入上面的公式,算出HWM的位置: 8-5=3 HWM所在的BLOCK ID是2632+3-1=2634,

OK,我們發現,此時HWM的位置已經發生變化,現在HWM的位置是在第3個BLOCK,其BLOCK ID是2634,所有資料檔案的ID是9(這個沒有發生變化,資料檔案還是原來的那個資料檔案,只是釋放了原來的自由空間),最後使用的塊數也變為3,也就是說已經使用了3塊,HWM就是在最後一個使用的塊上,即第3個塊上.大家可能會覺得奇怪,為什麼釋放空間後,未使用的塊還有5個啊?也就是說HWM之上還是有5個已分配但從未使用的塊.答案就跟HWM移動的規律有關.當我們在插入資料時,ORACLE首先在HWM之下的塊當中定位自由空間(通過自由列表FREELIST),如果FREELIST當中沒有自由塊了,ORACLE就開始往上擴充套件,而HWM也跟著往上移,每5塊移動一次.我們來看ORACLE的說明:

The high water mark is:
-Recorded in the segment header block
-Set to the beginning of the segment on the creation
-Incremented in five-block increments as rows are inserted
-Reset by the truncate command
-Never reset by the delete command
-Space above the high-water-mark can be reclaimed at the table level by using the following command:
ALTER TABLE DEALLOCATE UNUSED…

我們再來看看:SELECT COUNT(*) FROM TEST_TAB所花的時間:
SQL> SELECT COUNT(*) FROM TEST_TAB;
ELAPSED: 00:00:00.00
EXECUTION PLAN
----------------------------------------------------------

0 SELECT STATEMENT PTIMIZER=CHOOSE
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'TEST_TAB'

STATISTICS
----------------------------------------------------------
0 RECURSIVE CALLS
0 DB BLOCK GETS
3 CONSISTENT GETS
0 PHYSICAL READS
0 REDO SIZE
378 BYTES SENT VIA SQL*NET TO CLIENT
503 BYTES RECEIVED VIA SQL*NET FROM CLIENT
2 SQL*NET ROUNDTRIPS TO/FROM CLIENT
0 SORTS (MEMORY)
0 SORTS (DISK)
1 ROWS PROCESSED

很快,不到1s.


我們最後再來對錶作一次分析, 此時這個表目前使用的BLOCK為: 0,未使用的BLOCK(EMPTY_BLOCKS)為:0,總行數為(NUM_ROWS):0

從中我們也可以發現,分析表和SHOW_SPACE顯示的資料有點不一致.那麼哪個是準的呢?其實這兩個都是準的,只不過計算的方法有點不同.事實上,當你建立了一個物件如表以後,不管你有沒有插入資料,它都會佔用一些塊,ORACLE也會給它分配必要的空間.同樣,用ALTER TABLE MOVE釋放自由空間後,還是保留了一些空間給這個表.

最後,我們再來執行TRUNCATE命令,截斷這個表,看看段空間的使用狀況:

TRUNCATE TABLE TEST_TAB;

SQL> EXEC SHOW_SPACE('TEST_TAB','TEST');

TOTAL BLOCKS............................8
TOTAL BYTES.............................65536
UNUSED BLOCKS...........................5
UNUSED BYTES............................40960
LAST USED EXT FILEID....................9
LAST USED EXT BLOCKID...................2632
LAST USED BLOCK.........................3

我們發現TRUNCATE後和MOVE沒有什麼變化.

為了,最終驗證一下我上面的觀點,我再DROP一下表,然後新建這個表,看看這時在沒有插入任何資料之前,是否ORACLE確實有給這個物件分配必要的空間:

DROP TABLE TEST_TAB;
CREATE TABLE TEST_TAB(C1 NUMBER(10),C2 CHAR(100)) TABLESPACE RAINNY;
SQL> EXEC SHOW_SPACE('TEST_TAB','TEST');
TOTAL BLOCKS............................8
TOTAL BYTES.............................65536
UNUSED BLOCKS...........................5
UNUSED BYTES............................40960
LAST USED EXT FILEID....................9
LAST USED EXT BLOCKID...................2112
LAST USED BLOCK.........................3

即使我沒有插入任何一行記錄,ORACLE還是給它分配了8個塊.當然這個跟建表語句的INITIAL 引數及MINEXTENTS引數有關:請看TEST_TAB的儲存引數:


STORAGE
(
INITIAL 64K
MINEXTENTS 1
MAXEXTENTS UNLIMITED
);


也就是說,在這個物件建立以後,ORACLE至少給它分配一個區,初始大小是64K,一個標準塊的大小是8K,剛好是8個BLOCK.

總結:


在9I中:

(1)如果MINEXTENT 可以使ALTER TABLE TABLENAME DEALLOCATE UNUSED將HWM以上所有沒使用的空間釋放
(2)如果MINEXTENT >HWM 則釋放MINEXTENTS 以上的空間。如果要釋放HWM以上的空間則使用KEEP 0。
ALTER TABLE TABLESNAME DEALLOCATE UNUSED KEEP 0;
(3) TRUNCATE TABLE DROP STORAGE(預設值)命令可以將MINEXTENT 之上的空間完全釋放(交還給作業系統),並且重置HWM。


(4)如果僅是要移動HWM,而不想讓表長時間鎖住,可以用TRUNCATE TABLE REUSE STORAGE,僅將HWM重置。
(5)ALTER TABLE MOVE會將HWM移動,但在MOVE時需要雙倍的表空間,而且如果表上有索引的話,需要重構索引


(6)DELETE表不會重置HWM,也不會釋放自由的空間(也就是說DELETE空出來的空間只能給物件本身將來的INSERT/UPDATE使用,不能給其它的物件使用)


在ORACLE 10G:
(1)可以使用ALTER TABLE TEST_TAB SHRINK SPACE命令來聯機移動HWM,
(2)如果要同時壓縮表的索引,可以釋出:ALTER TABLE TEST_TAB SHRINK SPACE CASCADE

需要特別注意的是:

SHRINK SPACE 表會造成redo和undo增長過快,因為這個操作是把一部分高水位的行遷移到來降低hwm的,實際上是執行了dml操作,對大表或使用非常頻繁的表在壓縮之前尤其要慎重。一般情況下沒必要進行壓縮,而且即使在一個表刪除比較頻繁的情況下有時也不必壓縮,只要增加了相應數量的記錄,其空塊的比例也不會太大。另外要選在系統空閒的時候壓縮。

================================

  適用表,索引,大物件,IOT,物化檢視
  
  alter table tbname row movement
  保持HWM
  alter table tbname shrink space compact;
  回縮表與HWM
  alter table tbname shrink space;

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

相關文章