- Oracle表段中的高水位線HWM :
- 在Oracle數據的存儲中,可以把存儲空間想象爲一個水庫,數據想象爲水庫中的水。
- 水庫中的水的位置有一條線叫做水位線,在Oracle中,這條線被稱爲高水位線(High-warter mark,
- HWM)。
- 在數據庫表剛建立的時候,由於沒有任何數據,所以這個時候水位線是空的,也就是說HWM爲最低值
- 。當插入了數據以後,高水位線就會上漲,但是這裏也有一個特性,就是如果你採用delete語句刪
- 除數據的話,數據雖然被刪除了,但是高水位線卻沒有降低,還是你剛纔刪除數據以前那麼高的水
- 位。也就是說,這條高水位線在日常的增刪操作中只會上漲,不會下跌。HWM通常增長的幅度爲一次
- 5個數據塊.
- Select語句會對錶中的數據進行一次掃描,但是究竟掃描多少數據存儲塊呢,這個並不是說數據庫
- 中有多少數據,Oracle就掃描這麼大的數據塊,而是Oracle會掃描高水位線以下的數據塊。
- 理解高水位的作用:理解全表掃描的開銷(實驗:如果)
- @@@@@@
- 修正ORACLE表的高水位線
- ORACLE中,執行對錶的刪除操作不會降低該表的高水位線。而全表掃描將始終讀取一個段(extent)
- 中所有低於高水位線標記的塊。如果在執行刪除操作後不降低高水位線標記,則將導致查詢語句的
- 性能低下。rebuild, truncate, shrink,move 等操作會降低高水位。
- A、執行表重建指令 alter table table_name move;(把樓移到另一塊地)
- B、 執行alter table table_name shrink space; 此命令爲Oracle 10g新增功能,再執行該指令之
- 前必須允許行移動 alter table table_name enable row movement;
- C、 重建表
- 複製要保留的數據到臨時表t,drop原表,然後rename臨時表t爲原表
- D、 用邏輯導入導出: Emp/Imp
- E、. Alter table table_name deallocate unused
- DEALLOCATE UNUSED爲釋放HWM上面的未使用空間,但是並不會釋放HWM下面的自由空間,也不會移動
- HWM的位置.
- F、 推薦使用truncate.
- @@@@@
- ORACLE用HWM來界定一個段中使用的塊和未使用的塊.
- 舉個例子來說,當我們創建一個表時,ORACLE就會爲這個對象分配一個段.在這個段中,即使我們未插
- 入任何記錄,也至少有一個區被分配,第一個區的第一個塊就稱爲段頭(SEGMENT HEADE),段頭中就儲
- 存了一些信息,其中HWM的信息就存儲在此.此時,因爲第一個區的第一塊用於存儲段頭的一些信息,雖
- 然沒有存儲任何實際的記錄,但也算是被使用,此時HWM是位於第2個塊.當我們不斷插入數據到表後,
- 第1個塊已經放不下後面新插入的數據,此時,ORACLE將高水位之上的塊用於存儲新增數據,同時,HWM
- 本身也向上移.也就是說,當我們不斷插入數據時,HWM會往不斷上移,這樣,在HWM之下的,就表示使用
- 過的塊,HWM之上的就表示已分配但從未使用過的塊.
- HWM在插入數據時,當現有空間不足而進行空間的擴展時會向上移,但刪除數據時不會往下移.
- ORACLE 不會釋放空間以供其他對象使用,有一條簡單的理由:由於空間是爲新插入的行保留的,並
- 且要適應現有行的增長。被佔用的最高空間稱爲最高使用標記 (HWM),
- @@@
- ORACLE的全表掃描是讀取高水位標記(HWM)以下的所有塊.
- @@@
- 什麼樣的插入是在高水位上面進行插入的?(append操作(不檢查高水位線是否有數據,效率高,
- 不寫日誌,浪費空間))
- 當用直接路徑插入行時,即使HWM以下有空閒的數據庫塊,鍵入在插入數據時使用了append關鍵字,
- 則在插入時使用HWM以上的數據塊,此時HWM會自動增大。
- 例如,通過直接加載插入(用 APPEND 提示插入)或通過 SQL*LOADER 直接路徑 數據塊直接置於
- HWM 之上。它下面的空間就浪費掉了。
- @@@@
- 相關測試:
- SQL> create table tt (id number);此時表沒有分析,是原始的數據,即8個數據塊。
- SQL> select segment_name,segment_type,blocks from dba_segments where segment_nam
- e='TT';
- SEGMENT_NAME
- --------------------------------------------------------------------------------
- SEGMENT_TYPE BLOCK
- ------------------ ----------
- TT
- TABLE 8(段佔用了多少個塊)
- SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table
- _name='TT';
- TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
- ------------------------------ ---------- ---------- ------------
- TT
- declare
- i number;
- begin
- for i in 1..10000 loop
- insert into tt values(i);
- end loop;
- commit;
- end;
- /
- SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE
- segment_name='TT';
- SEGMENT_NAME SEGMENT_TYPE BLOCKS
- --------------- --------------- ----------
- TT TABLE 24
- 註釋:user_dbasegments中的BLOCKS 列代表該表中曾經使用過得數據庫塊的數目
- dba_dbasegments中的BLOCKS 列代表段佔用多少個塊
- SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE
- table_name='TT';
- TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
- --------------- ---------- ---------- ------------
- TT
- 此時表TT 佔用的數據庫已經是24個了。 但是user_tables 顯示的信息還是爲空。 因爲沒有做統計
- 分析。
- exec DBMS_STATS.GATHER_TABLE_STATS('SYS','TT');(收集統計信息)
- SQL> exec DBMS_STATS.GATHER_TABLE_STATS('SYS','TT');(收集統計信息)
- PL/SQL 過程已成功完成。
- SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE
- table_name='TT';
- TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
- --------------- ---------- ---------- ------------
- TT 10000 20 0
- 此時user_tables 已經有了數據,顯示的使用了20個數據塊。 但是empty_blocks 還是爲空。
- 這裏要注意的地方。 這個字段只有使用analyze 收集統計信息之後纔會有數據。
- 5) 使用analyze 收集統計信息
- SQL> ANALYZE TABLE TT COMPUTE STATISTICS;
- Table analyzed.
- SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE
- table_name='TT';
- TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
- --------------- ---------- ---------- ------------
- TT 10000 20 3
- 這個時候高水位在哪裏呢?20(20+3=23<24) 這裏有顯示空的數據庫有3個。
- 注意:20+3=23. 比佔用的24個數據塊少一個。因爲有一個數據庫塊被保留用作segment header。
- delete 數據
- 看是否會影響他的段大小
- delete from tt;
- commit
- SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE
- segment_name='TT';
- SEGMENT_NAME SEGMENT_TYPE BLOCKS
- --------------- --------------- ----------
- TT TABLE 24
- SQL>analyze table tt compute statistics;(算出高水位線在那一塊)
- SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table
- _name='TT';(blocks爲高水位線)
- TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
- ------------------------------ ---------- ---------- ------------
- TT 0 20 3
- 這裏我們可以證明了什麼:高水位不受delete 影響
- SQL>insert into tt select * from tt;(tt已經刪除沒有數據)
- SQL> insert into tt select rownum from dba_objects;
- 已創建50323行。
- SQL>analyze table tt compute statistics;
- SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table
- _name='TT';(查看高水位線(blocks))大於20
- TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
- ------------------------------ ---------- ---------- ------------
- TT 50323 79 0
- 這裏我們可以證明了什麼:高水位不受commit影響,只要有插入數據HWM就會增加
- @@@@@
- 釋放高水位(truncate)
- SQL> truncate table tt;
- 表被截斷。
- SQL> ANALYZE TABLE TT COMPUTE STATISTICS;
- 表已分析。
- SQL> select segment_name,segment_type,blocks from dba_segments where segment_nam
- e='TT';
- SEGMENT_NAME
- --------------------------------------------------------------------------------
- SEGMENT_TYPE BLOCKS
- ------------------ ----------
- TT
- TABLE 8(又回到原來的8)