關於高水位的知識

東北胖子發表於2018-08-19

一、對於手動段空間管理(MSSM)的表空間

  • 高水位標記(HWM)是指這個段空間中已使用和未使用的block的分界線,HWM之上的空間在格式化之前不能被使用。即在HWM以上的資料塊均為未格式化的塊,這些未格式化的塊在格式化之前是不能被 insert資料的。

  • 在資料庫事務中,當請求新的空閒塊並且現有空閒列表中的塊不能滿足要求時,HWM會向上移動,然後 格式化一組 資料塊並加入Free List提供使用。

  • 在HWM之下的資料塊也可能存在空閒的情況,當資料被刪除時,資料塊被釋放重新回到FreeList,又可以被其它資料變更所用,HWM通常只能向上增長,不會自動收縮。

    圖1 高水位示意圖

  • HWM會影響Oracle執行全表掃描時的讀取行為,對於全表掃描操作,Oracle必須讀取HWM下的所有資料塊,如果一個資料表由於DELETE操作刪除了大部分記錄,但是HWM並不會降低,所以再次執行全表掃描時,Oracle仍然需要讀取物件段中所有的資料塊(也就是HWM以下的所有資料塊)

  • 對於通常的物件,我人不太需要關注其HWM的影響,但是如果表的刪除操作非常頻繁,表中的在部分Block已經為空,那麼可能就需要關注其空間效能問題。


二、簡單的估算表中的空塊的資料

     透過dba_tables檢視查出表所佔用的blocks數量

SELECT blocks FROM dba_tables WHERE table_name='表名';

     透過rowid計算出實際表中的資料佔用blocks數量

     目前Oracle(8i以後版本)的rowid格式是 OOOOOO.FFF.BBBBBB.RRR共18位,佔用10個位元組,代表80位二進數,

     其中 O 代表 物件號,F代表檔案號,B代表塊號,R代表行號,這80位的方式 為:

      32bit obj# + 10bit rfile# + 22bit block# + 16bit row#

     因此我們透過這樣一個SQL就可以大概算出表佔用的block數量(取rowid的前15位)

SELECT COUNT(DISTINCT(SUBSTR(ROWID,1,15))) FROM 表名;

    兩步得出來的結果相除就可以得出使用資料塊佔用比和空塊的佔用比



三、對於自動段空間管理(ASSM)的表空間

  • 對於ASSM方式管理的段,在其段頭是會存在兩種高水位標記,分別是LHWM和HHWM,即低高水位和高高水位

  • 由於在ASSM管理方式下不存在Free List ,所以LHWM和HHWM概念被引入用於實現段空間管理,在ASSM管理模式下,當一個會話向表中插入資料時,資料庫首先 格式化一個位 圖塊(而不是像以前那樣格式化一組塊),這個點陣圖塊代替Free List用於跟蹤段中的資料塊的狀態變化,資料庫透過點陣圖塊去尋找空閒塊並在使用前對其進行格式化。

  • ASSM管理方式下的Segment 的LHWM和HHWM的特點如下:

       所有在HHWM以上的資料塊一定是未格式化的塊

       所有在LHWM以下的資料塊一定是格式化的塊

       在LHWM和HHWM之間的資料塊有可能是格式化的也有可能是未格式化的

        Oracle在全表掃描一個Segment時,會一直掃描到HHWM為止

  • 對於使用ASSM管理的Segment,可以透過Oracle提供的DBMS_SPACE直接計算其空間使用情況


  • create   or replace procedure show_space_assm(
    p_segname   in varchar2,
    p_owner   in varchar2 default user,
    p_type   in varchar2 default 'TABLE' )   
    as 
    l_fs1_bytes   number;
    l_fs2_bytes   number;
    l_fs3_bytes   number;
    l_fs4_bytes   number;
    l_fs1_blocks   number;
    l_fs2_blocks   number;
    l_fs3_blocks   number;
    l_fs4_blocks   number;
    l_full_bytes   number;
    l_full_blocks   number;
    l_unformatted_bytes   number;
    l_unformatted_blocks   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.space_usage(
    segment_owner      => p_owner,
    segment_name       => p_segname,
    segment_type       => p_type,
    fs1_bytes          => l_fs1_bytes,
    fs1_blocks         => l_fs1_blocks,
    fs2_bytes          => l_fs2_bytes,
    fs2_blocks         => l_fs2_blocks,
    fs3_bytes          => l_fs3_bytes,
    fs3_blocks         => l_fs3_blocks,
    fs4_bytes          => l_fs4_bytes,
    fs4_blocks         => l_fs4_blocks,
    full_bytes         => l_full_bytes,
    full_blocks        => l_full_blocks,
    unformatted_blocks   => l_unformatted_blocks,
    unformatted_bytes  => l_unformatted_bytes);  
    p('free   space 0-25% Blocks:',l_fs1_blocks); 
    p('free   space 25-50% Blocks:',l_fs2_blocks);
    p('free   space 50-75% Blocks:',l_fs3_blocks);
    p('free   space 75-100% Blocks:',l_fs4_blocks);
    p('Full   Blocks:',l_full_blocks);
    p('Unformatted   blocks:',l_unformatted_blocks);
    end;
    /
    


  • 我們知道,在ASSM下,block的空間使用分為free space: 0-25%,25-50%,50-75%,70-100%,full 這樣5中情況,show_space_assm會對需要統計的table彙總這5中型別的block的數量。

    我們來看table HWM1的空間使用情況:

    SQL> exec show_space_assm('HWM1','DLINGER');

    free space 0-25% Blocks:.................0

    free space 25-50% Blocks:...............1

    free space 50-75% Blocks:...............0

    free space 75-100% Blocks:..............8

    Full Blocks:.....................................417

    Unformatted blocks:.........................0

    這個結果顯示,table HWM1,full的block有417個,free space 為75-100% Block有8個,free space 25-50% Block有1個。當table HWM下的blocks的狀態大多為free space較高的值時,我們考慮來合併HWM下的blocks,將空閒的block釋放,降低table的HWM。


四、降低高水位的方法

  • 匯出/匯入與TRUNCATE結合

    truncate命令可以降低高水位,但是可能這種方法的場景非常少

    可以透過EXP匯出資料或者使用CTAS建立一張香表,然後Truncate表,再匯入或者insert回資料,但是對於不間斷服務的資料表並不合適

  • RENAME和INSERT結合

    對於連續使用的資料表,如果資料是以寫為主的日誌類資料,則可以透過RENAME將資料表更名,然後按原來的結構重建資料表,此時插入操作可以恢復,這個過程非常迅速,對於資料庫影響較小,然後可以將RENAME表中的資料插入回來,這就完成了資料整理,HWM可以降低,這種方法適用於寫為主的業務型別,不適合增刪改查頻繁的物件。

  • 線上重定義(DBMS_REDEFINITION)

    從Oracle 9I開始引入了線上重定義特性,透過DBMS_REDEFINITION包可以對錶進行線上重定義,如修改表欄位名稱、增加欄位等,當然也可以借用這個包進行空間整理。

    線上重定義過程中,Oracle透過中間的臨時表來記錄中間變化資料,完成重定義後可以將資料整合到重定義表中,資料庫的正常操作可以繼續進行。

  • Shrink特性

    從Oracle 10g開始引入了用於支援線上空間重整,這僦是聯機段空間回收功能 (Shrink Database Segments Online)

    聯機段收縮公對ASSM表空間中的表有效,Shrink的本質就是對錶執行一系列的DML操作,刪除表末端的稀疏行,並在表的頂端重新插入。透過這樣的一系列操作,可以填滿表段中的“漏洞”空間,逐步將所有剩餘空間留在表的末端,然後Oracle可以重置該表的HWM,釋放空間。由於Shrink是針對資料行進行處理的 ,在表上會獲得行級排他鎖,所以並不會影響全表的DML操作,這也是Online的意義所在,但是Shrink可能會產生大量Redo,影響歸檔量,在操作時需要考慮。

    由於回收段空間需要移動行資料,資料的rowid會發生變化,索引會被同時維護,也因此在執行Shrink之前,需要設定表的ENABLE ROW MOVEMENT屬性。

    但需要注意的是,由於段空間重整是透過DML操作來完成的,所以會產生額外的redo,如果資料表非常大,那麼產生的Redo可能是生產接受的


  • alter table 表名 enable row movement;
    
  • alter table 表名 shrink space;
    

    不支援Shrink的表:

    IOT mapping tables

    Tables with rowid based materialized views

    Tables with function-based indexes

    SECUREFILE LOBs

    Compressed tables

  • Move物件

    透過Move操作移動物件,可以降低HWM,但是Move之後,索引需要重建,而且在Move的過程中會影響線上應用,所以這種方法使用較為有限

  • 其它方法

    空間的重建始終是一個難題,各種方法都是以一定的效能犧牲為代價的,這就使得很多方法在實際的生產過程中並不可用,所以更好的辦法應該是從應用入手、從規劃入手,從最開始就能夠避免一些可能出現的問題。

    在最常採用的方法中,分割槽是一個常用的手段,涉及大量資料變更的資料表,很多可以透過分割槽來處理,由於分割槽表可以針對分割槽進行諸如DROP、TRUNCATE等操作,從而可以很容易地對分割槽進行維護,進而解決一系列的空間問題。

    當然分割槽並不是萬能的,其適用環境也是有限的,所以真正能夠解決問題的方法還是來自己我們自己,透過對Oracle各種技術的認識和了解後,我們才能夠制定出適合我們需要的空間維護手段。


注:文章內容來自《循序漸進Oracle》

      部分程式碼來自蓋老闆的部落格:

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

相關文章