oracle高水位線

 ORACLE在邏輯存儲上分4個粒度: 表空間, 段, 區 和 塊.

 

      1.1 塊: 是粒度最小的存儲單位,現在標準的塊大小是8K,ORACLE每一次I/O操作也是按塊來操作的,也就是說當ORACLE從數據文件讀數據時,是讀取多少個塊,而不是多少行.  每一個Block裏可以包含多個row.

 

       1.2 區: 由一系列相鄰的塊而組成,這也是ORACLE空間分配的基本單位,舉個例子來說,當我們創建一個表Dave時,首先ORACLE會分配一區的空間給這個表,隨着不斷的INSERT數據到Dave,原來的這個區容不下插入的數據時,ORACLE是以區爲單位進行擴展的,也就是說再分配多少個區給Dave,而不是多少個塊.

 

       1.3 段: 是由一系列的區所組成, 一般來說, 當創建一個對象時(表,索引),就會分配一個段給這個對象. 所以從某種意義上來說,段就是某種特定的數據.如CREATE TABLE Dave,這個段就是數據段,而CREATE INDEX ON Dave(NAME), ORACLE同樣會分配一個段給這個索引,但這是一個索引段了.查詢段的信息可以通過數據字典: SELECT * FROM USER_SEGMENTS來獲得.

 

       1.4 表空間: 包含段,區及塊.表空間的數據物理上儲存在其所在的數據文件中.一個數據庫至少要有一個表空間

ORACLE用HWM來界定一個段中使用的塊和未使用的塊。由於空間是爲新插入的行保留的,並且要適應現有行的增長。被佔用的最高空間稱爲最高使用標記 (HWM)

         1.當我們創建一個表時, ORACLE就會爲這個對象分配一個段, 在這個段中即使我們未插入任何記錄, 也至少有一個區被分配, 第一              個區的第一個塊就稱爲段頭塊(SEGMENT_HEADER), 段頭中就儲存了一些信息, 其中HWM的信息就存儲在此。

           此時, 因爲第一 個區的第一塊用於存儲段頭的一些信息, 雖然沒有存儲任何實際的記錄, 但也算是被使用, 此時HWM是位於第2個              塊, 當我們不斷插入數據後, 第一個塊已經放不下後面新插入的數據, 此時, ORACLE將高水位之上的塊用於存儲新增數據, 同時,             HWM本身也向上移, 也就是說, 當我們不斷插入數據時, HWM會不斷上移, 這樣, 在HWM之下的, 就表示使用過的塊。 HWM之上             的就表示已分配但從未使用過的塊。

        2 .HWM在插入數據時, 當現有空間不足而進行空間的擴展時會向上移, 但刪除數據時不會往下移。

        3 .HWM本身的信息是存儲在段頭 :

                  在段空間是手工管理方式時, ORACLE是通過FREELIST(一個單向鏈表)來管理段內的空間分配,

                  在段空間是自動管理方式時, ORACLE是通過BITMAP來管理段內的空間分配。

        4 .ORACLE的全表掃描是讀取高水位標記(HWM)以下的所有塊。

        5.HWM通常增長的幅度爲一次5個數據塊,原則上HWM只會增大,不會縮小,即使將表中的數據全部刪除,HWM還是爲原值,但            是如果我們在表上使用了truncate命令,則該表的HWM會被重新置爲0,這條高水位線在日常的增刪操作中只會上漲,不會下跌

 所以問題就產生了, 當用戶發出一個全表掃描時, ORACLE始終必須從段一直掃描到HWM, 即使它什麼也沒有發現。 該任務延長了全表  掃描的時間。

低HWM:

    在管理段的時候通常有兩種方法:手動管理段空間(Manual Segment Space Management )和自動段空間(Automatic Segment Space Management)

在手動段空間管理(Manual Segment Space Management)中,段中只有一個HWM,但是在Oracle 9i Release1才添加的自動段空間管理(Automatic Segment Space Management)中,又有了一個低HWM的概念出來。爲什麼有了HWM還又有一個低HWM呢,這個是因爲自動段空間管理的特性造成的。

在手段段空間管理中,當數據插入以後,如果是插入到新的數據塊中,數據塊就會被自動格式化等待數據訪問。而在自動段空間管理中,數據插入到新的數據塊以後,數據塊並沒有被格式化,而是在第一次訪問這個數據塊的時候才格式化這個塊。所以我們又需要一條水位線,用來標示已經被格式化的塊。這條水位線就叫做低HWM。一般來說,低HWM肯定是低於等於HWM的。

HWM數據庫的操作有如下影響:

a) 全表掃描通常要讀出直到HWM標記的所有的屬於該表數據庫塊,即使該表中沒有任何數據。

b) 即使HWM以下有空閒的數據庫塊,鍵入在插入數據時使用了append關鍵字,則在插入時使用HWM以上的數據塊,此時HWM會自動增大。

使用delete不能使高水位線降低,使用truncate可以使用高水位線降低,所以當刪除整表數據或者分區最好是用truncate,
當用delete刪除大表數據時後,還是要重建表,這樣可以降低高水位線

 

TRUNCATE命令回收了由delete命令產生的空閒空間爲了保留由delete命令產生的空閒空間,可以使用TRUNCATE TABLE 55LINUX REUSE STORAGE.用此命令後,該表還會是原先的1024塊

 

採用TRUNCATE語句刪除一個表的數據的時候,類似於重新建立了表,不僅把數據都刪除了,還把HWM給清空恢復爲0。所以如果需要把表清空,在有可能利用TRUNCATE語句來刪除數據的時候就利用TRUNCATE語句來刪除表,特別是那種數據量有可能很大的臨時存儲表。

在9i的時候,一個很成熟的碎片整理技術。

整理表碎片通常的方法是move表

高水位以下合併碎片,不移動高水位

當然move是不能在線進行的,

不跟參數表還是在原來的表空間

而且move後相應的索引也會失效,需要重建

如果以後還要繼續向這個表增加數據,沒有必要move,只是釋放出來的空間,只能這個表用,其他的表或者segment無法使用該空間

table在進行move操作時,我們只能對它進行select的操作,DML會全部阻塞(move生成的undo和redo是非常少的)。反過來說,當我們的一個session對table進行DML操作且沒有commit時, 
在另一個session中是不能對這個table進行move操作的,否則oracle會返回這樣的錯誤信息:ORA-00054(資源正忙)
 

 

 

   oracle在10g時候提供了shrink space碎片整理功能,不僅能整理碎片還可以收縮高水位,索引也不需要重建。

shrink的一個優點是能在線進行,不影響表上的DML操作,當然,併發的DML操作在shrink結束的時刻會出現短暫的block; 
shrink的另外一個優點是在碎片整理結束後,表上相關的index仍然enable。shrink在整理表碎片的時候,行源的rowid已經發生改變,那爲什麼相關的索引還能enable呢?其實oracle在進行shrink的時候會對相應的索引進行維護,以保證index在shrink結束的時候index仍然有效。這個維護不同於索引rebuild,不會對索引的空間進行整理,shrink有cascede選項,如果在shrink的時候加上該選項,就會對錶上相應的索引空間進行整理。

 

SHRINK(收縮) TABLE(表空間收縮)

實質上構造一個新表(在內部表現爲一系列的DML操作,即將副本插入新位置,刪除原來位置的記錄)靠近末尾處(右端)數據塊中的記錄往開始處(左端)的空閒空間處移動(DML操作),不會引起DML觸發器當所有可能的移動被完成,高水位線將會往左端移動(DDL操作),新的高水位線右邊的空閒空間被釋放(DDL操作)

    

   從10g開始, ORACLE開始提供SHRINK的命令, 假如我們的表空間中支持自動段空間管理(ASSM), 就可以使用這個特性縮小段, 即降低HWM。 10g的這個新特性, 必須啓用行記錄轉移(enable row movement)僅僅適用於堆表,且位於自動段空間管理的表空間(堆表包括:標準表,分區表,物化視圖容器,物化視圖日誌表)

       如果經常在表上執行DML操作, 會造成數據庫塊中數據分佈稀疏, 浪費大量空間。 同時也會影響權標掃描的性能。 因爲全表掃描需要訪問更多的數據塊。從oracle10g開始, 表可以通過SHRINK來重組數據使數據分佈更緊密, 同時降低HWM釋放空閒數據塊。       

shrink必須開啓行遷移功能。

segment shrink分爲兩個階段:

1 數據重組(compact):

執行ALTER TABLE test SHRINK SPACE compact:

通過一系列insert、delete操作, 將數據儘量排列在段的前面。 在這個過程中需要在表上加RX鎖, 即只在需要移動的行上加鎖。由於涉及到rowid的改變, 需要enable row movement, 同時要disable基於rowid的trigger。 這一過程對業務影響比較小。

2. HWM調整:

執行ALTER TABLE test SHRINK SPACE:

調整HWM位置, 釋放空閒數據塊第一步中的結果已經存儲到磁盤,不會重新在整理碎片,只是收縮高水位,釋放空間。此過程需要在表上加X鎖, 會造成表上的所有DML語句阻塞。在業務特別繁忙的系統上可能造成比較大的影響。

 

 

如果系統業務比較繁忙, 可以先執行shrink space compact重組數據, 然後在業務不忙的時候再執行shrink space降低HWM釋放空閒數據塊。

 

 

 

我們先看下shrink的工作原理,shrink的算法是從segment的底部開始,移動row到segment的頂部,移動的過程相當於delete/insert操作的組合,在這個過程中會產生大量的undo和redo信息。在HP Unix上還存在BUG,在10.1.0.3.0中,在shrink的時候可能會觸發BUG 3888229,產生巨大數量的redo和undo。move是直接移動數據塊的位置,鑑於上面的原因,在使用shrink的時候,耗時可能非常長,通常慢於move。

對於空間的要求,shrink不需要額外的空間,move需要兩倍的空間。

通過上面的分析,shrink雖然有online的特性,但是也存在很多問題,所以,在進行表碎片整理的時候,還是建議停機檢修,使用move,以下是一些move時候的注意點: 
1、move前最好邏輯備份待整理的表; 
2、對於大表,建議開啓並行和nologging 
alter table test move nologging parallel 2; 
3、整理完畢後重建相關的索引 
alter index ind_test rebuild nologging parallel 2; 
4、恢復表和索引的並行度、logging 
alter table test logging parallel 1;

 
1. move過程中需要額外的表空間,需要的大小大約等於當前表中數據量的大小,move結束後立即釋放該額外空間。 
2. move過程中對錶加排它鎖,會影響其他session的DML操作。 
3. move操作並不會維護索引,因此move完畢後需要對索引rebuild。 
4. move操作會降低HWM,但是並不會釋放HWM以上的空塊,也就是說,move只會對HWM以下的塊進行操作。 
5. move操作的一些相關測試數據:以2000000數據(233M)爲例,刪除800000條數據,執行move操作。 
大概用時4秒,共產生了319K的redo,56K的undo。表由233M縮小至145M。 
6. move操作可以完全消除行遷移。 
7. move操作後,爲表分配的數據段位置發生了改變,即段頭塊的位置發生了改變。
shrink過程中並沒有用到額外的表空間。
shrink操作其實可以分爲兩步: 
第一步:對數據進行重組,即只會整理碎片,不會降低高水位,也就是說不會釋放空間。 
通過一系列的delete/insert組合來完成,具體的語法是 alter table t1 shrink space compact。該過程會在表上加共享鎖,在移動的行中加排它鎖。並且會維護索引。 
第二步:降低HWM,回收空間,與move不同的是,shrink可以回收HWM以上的塊。該過程會在表上加排它鎖,因此業務繁忙時並不適合執行該降低HWM的操作。
shrink操作會維護索引,但是不會對索引進行碎片整理。如果加入cascade選項,那麼維護索引的同時會對索引進行碎片整理。
shrink操作的一些相關測試數據:以2000000數據(233M)爲例,刪除800000條數據,分兩步執行shrink操作。 
數據重組大概用時1分鐘58秒,共產生了895M的redo,353M的undo。回收HWM階段僅用1秒,產生了4K的redo,1K的undo。表由233M縮小至226M。
shrink操作不能完全消除行遷移。
shrink操作後,爲表分配的數據段位置並沒有發生變化,即段頭塊的位置沒有改變。
 
create table HWM as select * from dba_objects;
 
SQL> SELECT segment_name, segment_type, blocks 
     FROM dba_segments
     WHERE segment_name='HWM';    
    
     DBA_SEGMENTS.BLOCKS 表示分配給這個表的所有的數據庫塊的數目
 
SQL> ANALYZE TABLE hwm ESTIMATE STATISTICS;          
 
SQL> SELECT table_name,num_rows,blocks,empty_blocks
     FROM user_tables
     WHERE table_name='HWM';
    
USER_TABLES.BLOCKS表示已經使用過的數據庫塊的數目,即水線。
USER_TABLES.EMPTY_BLOCKS 代表分配給該表,
但是在水線以上的數據庫塊,即從來沒有使用的數據塊。

BLOCKS + EMPTY_BLOCKS (700+323=1023)比DBA_SEGMENTS.BLOCKS少1個數據庫塊,
這是因爲有一個數據庫塊被保留用作segment header。
DBA_SEGMENTS.BLOCKS 表示分配給這個表的所有的數據庫塊的數目。
USER_TABLES.BLOCKS表示已經使用過的數據庫塊的數目。
 
SQL> SELECT COUNT (DISTINCT
     DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)||
     DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "Used"
     FROM hwm;
     
有多少塊容納數據
 
SQL> delete from hwm;         
SQL> commit;
SQL> ANALYZE TABLE hwm ESTIMATE STATISTICS; 
SQL> SELECT table_name,num_rows,blocks,empty_blocks
     FROM user_tables
     WHERE table_name='HWM';
 
SQL> TRUNCATE TABLE hwm;  
SQL> ANALYZE TABLE hwm ESTIMATE STATISTICS;                  
SQL> SELECT table_name,num_rows,blocks,empty_blocks
     FROM user_tables
     WHERE table_name='HWM';

 

 
move

alter table xxx move    

--壓縮快之後所有索引都會失效,需要重建一下索引
ALTER INDEX INDEX_NAME REBUILD;

 

高水位以下合併碎片,同時壓縮表,不移動高水位。
alter table xxx move compress 

 

釋放未

使用空

DEALLOCATE UNUSED爲釋放HWM上面的未使用空間,但是並不會釋放HWM下面的自由空間,也不會移動HWM的位置.

Alter  table table_name deallocate unused

 
查詢失效索引語句 select index_name,table_name,tablespace_name,status From dba_indexes Where owner='ISC' And status<>'VALID';  
 
select file_id,bytes/1024/1024 
from dba_free_space 
where tablespace_name='TEST';
 
 

普通表

         Sql腳本,改腳本會生成相應的語句

         select'alter table '||table_name||' enable row movement;'||chr(10)||'alter table '||table_name||' shrink space;'||chr(10)from user_tables;

         select'alter index '||index_name||' shrink space;'||chr(10)from user_indexes;

         分區表

         進行shrink space時 發生ORA-10631錯誤.shrink space有一些限制.

         在表上建有函數索引(包括全文索引)會失敗。

         Sql腳本,改腳本會生成相應的語句    

 
 
select 'alter table '||table_name||' enable row movement;'||chr(10)||'
alter table '||table_name||' shrink space;'||chr(10) 
from user_tables where ;
         

select 'alter index '||index_name||' shrink space;'||chr(10) 
from user_indexes 
where uniqueness='NONUNIQUE' ;
         

select 'alter table '||segment_name||' modify subpartition '
||partition_name||' shrink space;'||chr(10) 
from 
user_segments 
where segment_type='TABLE SUBPARTITION' ';
 
啓動關閉行遷移

alter table table_name enable row movement ;

alter table table_name disable row movement; 

注意, alter table table_name row movement語句會造成引用表table_name的對象(如存儲過程、包、視圖等)變爲無效。 需要執行utlrp.sql來編譯無效的對象。 

 
把碎片率高的表找出,按表的空間大小排序找出來,不支持壓縮表 select 'drop table ' || segment_name || ' purge;', sum(bytes)/1024/1024 Mbytese 
from user_segments a , user_tables b
where segment_type='TABLE'  
and a.segment_name=b.TABLE_NAME 
and b.COMPRESSION='DISABLED' 
group by segment_name,COMPRESSION 
order by sum(bytes)/1024/1024 desc;
 
SHRINK(收縮) 

alter table table_name shrink space [<null> | compact | cascade] ;

大表可同時降低表自身和表空間的高水位線,小表則只可以降低表自身的高水位線

 

收縮表, 相當於把塊中數據打結實了, 但會保持high water mark 。
alter table table_name shrink space compact ;
 
收縮表, 降低high water mark
alter table table_name shrink space ;  

 

收縮表, 降低high water mark, 並把相關索引也要收縮一下。
alter table table_name shrink space cascade ; 

回縮索引。
alter index idx_name shrink space ; 

 

 

統計信息

因爲所有的信息都是根據dba_tables,表的信息是根據統計信息得到的,所以如果統計信息不準確,那麼整個搜索的結果都可能是錯誤的

exec dbms_stats.gather_table_stats('user','table_name');

exec dbms_stats.gather_table_stats(user,'test1',estimate_percent=>100);

exec dbms_stats.gather_table_stats(user,'ISC_USER',CASCADE=>TRUE);

 

select table_name,last_analyzed from user_tables where table_name = 'ISC_USER' order by last_analyzed desc ;

 
 查找數據庫中某個表空間下,可以實際存儲和需要的表空間差別最大的表
SELECT 
NUM_ROWS,AVG_ROW_LEN*NUM_ROWS/1024/1024/0.9 NEED, BLOCKS*8/1024 TRUE,
(BLOCKS*8/1024-AVG_ROW_LEN*NUM_ROWS/1024/1024/0.9) RECOVER_MB,
TABLE_NAME
FROM dba_tables
WHERE tablespace_name='PSAPSR3' 
AND BLOCKS*8/1024-AVG_ROW_LEN*NUM_ROWS/1024/1024/0.9>100
SELECT table_name,
ROUND((blocks * 8/1024), 2) "高水位空間 M",
ROUND((num_rows * avg_row_len / 1024/1024), 2) "真實使用空間 M",
ROUND((blocks * 10 / 100) * 8, 2) "預留空間(pctfree) M",
ROUND((blocks * 8 - (num_rows * avg_row_len / 1024) -blocks * 8 * 10 / 100), 2) 
"浪費空間 M",
((blocks * 8-(num_rows * avg_row_len / 1024))/1024)/(blocks * 8/1024) 
"浪費空間 %"
FROM user_tables
WHERE table_name = 'ISC_USER';
 

Oracle 9i:

       (1)如果是INEXTENT, 可以使alter table tablename deallocate unused將HWM以上所有沒使用的空間釋放

       (2) 如果MINEXTENT >HWM 則釋放MINEXTENTS 以上的空間。如果要釋放HWM以上的空間則使用KEEP 0。

       SQL>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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章