Oracle 降低高水位線的方法


高水位(HIGH WARTER MARK,HWM)好比水庫中儲水的水位,用於描述數據庫中段的擴展方式。高水位對全表掃描方式有着至關重要的影響。當使用DELETE刪除表記錄時,高水位並不會下降,隨之導致的是全表掃描的實際開銷並沒有任何減少。

例如,首先新建一張空表,大小占用64K,然后插入數據直到表大小變為50G,此時使用DELETE刪除所有的數據並且提交,這個時候查詢表的大小的時候依然是50G,這就是因為表的高水位沒有釋放的緣故,而在這時如果使用“SELECT * FROM TABLE_NAME;”語句來查詢數據的話,那么查詢過程就會很慢,因為Oracle要執行全表掃描,從高水位下所有的塊都得去掃描,直到50G的所有塊全部掃描完畢。曾遇到一個同事使用DELETE刪除了一個很大的分區表,然后執行SELECT查詢很久都沒有結果,以為是數據庫HANG住了,其實這個問題是由於高水位的緣故。所以,表執行了TRUNCATE操作,再次SELECT的時候就可以很快返回結果了。

釋放表的高水位通常有如下幾種辦法:

(1)對表進行MOVE操作:ALTER TABLE TABLE_NAME MOVE;。若表上存在索引,則記得重建索引。

(2)對表進行SHRINK SPACE操作:ALTER TABLE TABLE_NAME SHRINK SPACE;,注意,在執行該指令之前必須開啟行移動:ALTER TABLE TABLE_NAME ENABLE ROW MOVEMENT;。該方法的優點是:在碎片整理結束后,表上相關的索引仍然有效,缺點是會產生大量的UNDO和REDO。

(3)復制要保留的數據到臨時表T,DROP原表,然后RENAME臨時表T為原表。

(4)exp/imp或expdp/impdp重構表。

(5)若表中沒有數據則直接使用TRUNCATE來釋放高水位。


如何找出系統中哪些表擁有高水位呢?這里給出兩種辦法,①比較表的行數和表的大小關系。如果行數為0,而表的當前占用大小減去初始化時的大小(INITIAL_EXTENT)后依然很大,那么說明該表有高水位。②行數和塊數的比率,即查看一個塊可以存儲多少行數據。如果一個塊存儲的行數少於5行甚至更少,那么說明有高水位。注意,這兩種方法都不是十分准確,需要再對查詢結果進行篩選。需要注意的是,在查詢表的高水位時,首先需要分析表,以得到最准確的統計信息。

下面給出用於查詢高水位的幾個SQL語句:

SELECT D.OWNER,

       ROUND(D.NUM_ROWS / D.BLOCKS, 2),

       D.NUM_ROWS,

       D.BLOCKS,

       D.TABLE_NAME,

 ROUND((d.BLOCKS*8-D.INITIAL_EXTENT/1024)/1024)  t_size

  FROM DBA_TABLES D

 WHERE D.BLOCKS > 10

   AND ROUND(D.NUM_ROWS / D.BLOCKS, 2) < 5

 AND d.OWNER NOT LIKE '%SYS%' ;

 

或:

SELECT OWNER,

       SEGMENT_NAME TABLE_NAME,

       SEGMENT_TYPE,

       GREATEST(ROUND(100 * (NVL(HWM - AVG_USED_BLOCKS, 0) /

                      GREATEST(NVL(HWM, 1), 1)),

                      2),

                0) WASTE_PER

  FROM (SELECT A.OWNER OWNER,

               A.SEGMENT_NAME,

               A.SEGMENT_TYPE,

               B.LAST_ANALYZED,

               A.BYTES,

               B.NUM_ROWS,

               A.BLOCKS BLOCKS,

               B.EMPTY_BLOCKS EMPTY_BLOCKS,

               A.BLOCKS - B.EMPTY_BLOCKS - 1 HWM,

               DECODE(ROUND((B.AVG_ROW_LEN * NUM_ROWS *

                            (1 + (PCT_FREE / 100))) / C.BLOCKSIZE,

                            0),

                      0,

                      1,

                      ROUND((B.AVG_ROW_LEN * NUM_ROWS *

                            (1 + (PCT_FREE / 100))) / C.BLOCKSIZE,

                            0)) + 2 AVG_USED_BLOCKS,

               ROUND(100 *

                     (NVL(B.CHAIN_CNT, 0) / GREATEST(NVL(B.NUM_ROWS, 1), 1)),

                     2) CHAIN_PER,

               B.TABLESPACE_NAME O_TABLESPACE_NAME

          FROM SYS.DBA_SEGMENTS A, SYS.DBA_TABLES B, SYS.TS$ C

         WHERE A.OWNER = B.OWNER

           AND SEGMENT_NAME = TABLE_NAME

           AND SEGMENT_TYPE = 'TABLE'

           AND B.TABLESPACE_NAME = C.NAME)

 WHERE GREATEST(ROUND(100 * (NVL(HWM - AVG_USED_BLOCKS, 0) /

                      GREATEST(NVL(HWM, 1), 1)),

                      2),

                0) > 50

   AND OWNER NOT LIKE '%SYS%'

   AND BLOCKS > 100

 ORDER BY WASTE_PER DESC;

 

最后再次提醒各位讀者,若表執行了大量的DELETE操作后,則最好回收一下表的高水位。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM