2011年07月25日 09:22:26sql
閱讀數:15483數據庫
--====================
-- 收縮表段(shrink space)
--====================
1、表的增加方式
當表被建立後,隨着記錄的不斷插入,組成表的區間會被填滿,若是啓用了自動擴展,則當區間填滿後,會分配新的區間。假定高水
位線隨着記錄的增長從最左端往右端來移動,當到底部區間的尾端時,則新的區間將會被分配。
2、表可收縮的原理
隨着記錄的增長高水位線不斷的右移,記錄的刪除不會致使高水位線往回(左)移動
刪除記錄後的空閒空間(高水位線左側)儘管可使用,但其稀疏性致使空間空閒
注:完整的表掃描所耗費的時間不會由於記錄的減小(刪除)而減小
3、使用 alter table tbname shrink space 來收縮表段
1. 實現原理
實質上構造一個新表(在內部表現爲一系列的DML操做,即將副本插入新位置,刪除原來位置的記錄)
靠近末尾處(右端)數據塊中的記錄往開始處(左端)的空閒空間處移動(DML操做),不會引發DML觸發器
當全部可能的移動被完成,高水位線將會往左端移動(DDL操做)
新的高水位線右邊的空閒空間被釋放(DDL操做)
2. 實現前提條件
必須啓用行記錄轉移(enable row movement)
僅僅適用於堆表,且位於自動段空間管理的表空間(堆表包括:標準表,分區表,物化視圖容器,物化視圖日誌表)
3. 不能實現收縮的表
羣集表
具備LONG類型列的表
LOB段(儘管表自己能夠被縮小),注,10gR2之後版本支持對LOB段的收縮
具備基於提交的物化視圖的表(由於禁用了觸發器)
具備rowid物化視圖的表(由於rowid發生了變化)
IOT映射表IOT溢出段
索引基於函數的表
未啓用行記錄轉移的堆表
4. 段收縮的優勢
提升緩存利用率,提升OLTP的性能
減小磁盤I/O,提升訪問速度,節省磁盤空間
段收縮是在線的,索引在段收縮期間維護,不要求額外的磁盤空間
5. 兩個選項
cascade:縮小表及其索引,並移動高水位線,釋放空間
compact:僅僅是縮小表和索引,並不移動高水位線,不釋放空間
alter table tbname shrink space 至關於帶cascade參數
4、實戰演習
1. 查看須要收縮的表段的基本狀況,此處爲表big_table 緩存
SQL> col SEGMENT_NAME format a20
性能優化
SQL> select OWNER,SEGMENT_NAME,BYTES/1024/1024,BLOCKS from dba_segments
函數
2 where owner='SCOTT' and SEGMENT_NAME='BIG_TABLE';
工具
OWNER SEGMENT_NAME BYTES/1024/1024 BLOCKS
性能
------------------------------ -------------------- --------------- ----------
優化
SCOTT BIG_TABLE 120 15360
this
SQL> select table_name,blocks,empty_blocks from dba_tables
spa
2 where table_name='big_table' and owner='scott'; -->未更新統計信息前BLOCKS,EMPTY_BLOCKS列爲空
TABLE_NAME BLOCKS EMPTY_BLOCKS
------------------------------ ---------- ------------
BIG_TABLE
SQL> exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'BIG_TABLE',estimate_percent=>30);
PL/SQL procedure successfully completed.
SQL> select TABLE_NAME,BLOCKS,EMPTY_BLOCKS from dba_tables
2 where TABLE_NAME='BIG_TABLE' and owner='SCOTT';
TABLE_NAME BLOCKS EMPTY_BLOCKS
------------------------------ ---------- ------------
BIG_TABLE 14590 0 -->使用gather_table_stats時不會統計EMPTY_BLOCKS塊
SQL> analyze table big_table compute statistics; -->使用analyze更新統計信息後EMPTY_BLOCKS獲得數據
Table analyzed.
SQL> select TABLE_NAME,BLOCKS,EMPTY_BLOCKS from dba_tables
2 where TABLE_NAME='BIG_TABLE' and owner='SCOTT';
TABLE_NAME BLOCKS EMPTY_BLOCKS
------------------------------ ---------- ------------
BIG_TABLE 14590 770
SQL> set serveroutput on;
SQL> exec show_space('BIG_TABLE','SCOTT'); -->使用show_space過程或的BIG_TABLE上的空間分配信息
Unformatted Blocks ..................... 0
FS1 Blocks (0-25) ...................... 0 -->空閒度爲0-25%的塊數。FS1,FS2,FS3,FS4爲空閒度所佔的百分比
FS2 Blocks (25-50) ..................... 0
FS3 Blocks (50-75) ..................... 0
FS4 Blocks (75-100)..................... 0
Full Blocks ............................ 14,427
Total Blocks............................ 15,360
Total Bytes............................. 125,829,120
Total MBytes............................ 120
Unused Blocks........................... 770
Unused Bytes............................ 6,307,840
Last Used Ext FileId.................... 4
Last Used Ext BlockId................... 16,521
Last Used Block......................... 254
PL/SQL procedure successfully completed.
2. 刪除記錄以後,進行收縮表段
SQL> delete from big_table where owner in ('SCOTT','SYSTEM'); -->刪除記錄
8715 rows deleted.
SQL> commit;
Commit complete.
SQL> alter table big_table shrink space; -->實施shrink,提示沒有啓用ROW MOVEMENT
alter table big_table shrink space
*
ERROR at line 1:
ORA-10636: ROW MOVEMENT is not enabled
SQL> alter table big_table enable row movement; -->開啓row movement
Table altered.
SQL> alter table big_table shrink space; -->shrink成功
Table altered.
SQL> exec show_space('BIG_TABLE','SCOTT'); -->從下面的結果中能夠看到塊數以及總大小已經變小
Unformatted Blocks ..................... 0
FS1 Blocks (0-25) ...................... 1
FS2 Blocks (25-50) ..................... 1
FS3 Blocks (50-75) ..................... 0
FS4 Blocks (75-100)..................... 0
Full Blocks ............................ 14,318
Total Blocks............................ 14,488
Total Bytes............................. 118,685,696
Total MBytes............................ 113
Unused Blocks........................... 5
Unused Bytes............................ 40,960
Last Used Ext FileId.................... 4
Last Used Ext BlockId................... 16,521
Last Used Block......................... 147
PL/SQL procedure successfully completed.
3. 驗證cascade與compact的差別
SQL> delete from big_table where rownum<8000; -->再次刪除一些記錄
7999 rows deleted.
SQL> alter table big_table shrink space compact; -->使用compact方式收縮表段
Table altered.
SQL> exec show_space('BIG_TABLE','SCOTT');
Unformatted Blocks ..................... 0
FS1 Blocks (0-25) ...................... 1
FS2 Blocks (25-50) ..................... 2
FS3 Blocks (50-75) ..................... 0
FS4 Blocks (75-100)..................... 103
Full Blocks ............................ 14,214 --僅有的變化爲14318-14214=104塊,即徹底填滿的數據塊減小了104塊
Total Blocks............................ 14,488 --數據的總塊數及總大小並無減小,即未移動高水位線
Total Bytes............................. 118,685,696
Total MBytes............................ 113
Unused Blocks........................... 5
Unused Bytes............................ 40,960
Last Used Ext FileId.................... 4
Last Used Ext BlockId................... 16,521
Last Used Block......................... 147
PL/SQL procedure successfully completed.
SQL> alter table big_table shrink space cascade; -->使用cascade方式收縮,
Table altered.
SQL> exec show_space('BIG_TABLE','SCOTT');
Unformatted Blocks ..................... 0
FS1 Blocks (0-25) ...................... 1
FS2 Blocks (25-50) ..................... 2
FS3 Blocks (50-75) ..................... 0
FS4 Blocks (75-100)..................... 0
Full Blocks ............................ 14,214
Total Blocks............................ 14,384 -->總塊數及總大小均已減小
Total Bytes............................. 117,833,728
Total MBytes............................ 112
Unused Blocks........................... 4
Unused Bytes............................ 32,768
Last Used Ext FileId.................... 4
Last Used Ext BlockId................... 16,521
Last Used Block......................... 44
PL/SQL procedure successfully completed.
-->收縮以後索引依然有效
SQL> select OWNER,INDEX_NAME,STATUS from dba_indexes where TABLE_NAME='BIG_TABLE';
OWNER INDEX_NAME STATUS
------------------------------ ------------------------------ --------
SCOTT BIG_TABLE_PK VALID
5、語法總結:
ALTER TABLE <table_name> ENABLE ROW MOVEMENT -->前提條件
ALTER TABLE <table_name> SHRINK SPACE [ <NULL> | COMPACT | CASCADE ];
ALTER TABLE <table_name> SHRINK SPACE COMPCAT; -->縮小表和索引,不移動高水位線,不釋放空間
ALTER TABLE <table_name> SHRINK SPACE; -->收縮表,下降高水位線;
ALTER TABLE <table_name> SHRINK SPACE CASCADE; -->收縮表,下降高水位線,而且相關索引也要收縮一下
ALTER TABLE <table_name> MODIFY LOB (lob_column) (SHRINK SPACE); -->收縮LOB段
ALTER INDEX IDXNAME SHRINK SPACE; -->索引段的收縮,同表段
6、批量收縮腳本
1. 普通表(根據相應需求修改下面的語句生產相應腳本)
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;
2. 分區表的處理
分區表進行shrink space時發生ORA-10631錯誤.shrink space有一些限制.
在表上建有函數索引(包括全文索引)會失敗。
--根據相應需求修改下面的語句生產相應腳本
select 'alter table '||owner||'.'||table_name||' enable row movement;'
||chr(10)||'alter table '||owner||'.'||table_name||' shrink space;'||chr(10) from dba_tables
where owner=upper('&input_owner');
select 'alter index '||owner||'.'||index_name||' shrink space;'
||chr(10) from dba_indexes where uniqueness='NONUNIQUE' ;
select 'alter table '||owner||'.'||segment_name||' modify partition '||partition_name||' shrink space;'
||chr(10) from dba_segments where segment_type='TABLE PARTITION';
3. 附show_space腳本(來自Tom大師)
CREATE OR REPLACE PROCEDURE show_space
(
p_segname IN VARCHAR2,
p_owner IN VARCHAR2 DEFAULT USER,
p_type IN VARCHAR2 DEFAULT 'TABLE',
p_partition IN VARCHAR2 DEFAULT NULL
)
-- this procedure uses authid current user so it can query DBA_*
-- views using privileges from a ROLE, and so it can be installed
-- once per database, instead of once per user who wanted to use it
AUTHID CURRENT_USER AS
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;
l_segment_space_mgmt VARCHAR2(255);
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;
-- inline procedure to print out numbers nicely formatted
-- with a simple label
PROCEDURE p
(
p_label IN VARCHAR2,
p_num IN NUMBER
) IS
BEGIN
dbms_output.put_line(rpad(p_label, 40, '.') ||
to_char(p_num, '999,999,999,999'));
END;
BEGIN
-- this query is executed dynamically in order to allow this procedure
-- to be created by a user who has access to DBA_SEGMENTS/TABLESPACES
-- via a role as is customary.
-- NOTE: at runtime, the invoker MUST have access to these two
-- views!
-- this query determines if the object is an ASSM object or not
BEGIN
EXECUTE IMMEDIATE 'select ts.segment_space_management
from dba_segments seg, dba_tablespaces ts
where seg.segment_name = :p_segname
and (:p_partition is null or
seg.partition_name = :p_partition)
and seg.owner = :p_owner
and seg.tablespace_name = ts.tablespace_name'
INTO l_segment_space_mgmt
USING p_segname, p_partition, p_partition, p_owner;
EXCEPTION
WHEN too_many_rows THEN
dbms_output.put_line('This must be a partitioned table, use p_partition => ');
RETURN;
END;
-- if the object is in an ASSM tablespace, we must use this API
-- call to get space information, otherwise we use the FREE_BLOCKS
-- API for the user-managed segments
IF l_segment_space_mgmt = 'AUTO' THEN
dbms_space.space_usage(p_owner,
p_segname,
p_type,
l_unformatted_blocks,
l_unformatted_bytes,
l_fs1_blocks,
l_fs1_bytes,
l_fs2_blocks,
l_fs2_bytes,
l_fs3_blocks,
l_fs3_bytes,
l_fs4_blocks,
l_fs4_bytes,
l_full_blocks,
l_full_bytes,
p_partition);
p('Unformatted Blocks ', l_unformatted_blocks);
p('FS1 Blocks (0-25) ', l_fs1_blocks);
p('FS2 Blocks (25-50) ', l_fs2_blocks);
p('FS3 Blocks (50-75) ', l_fs3_blocks);
p('FS4 Blocks (75-100)', l_fs4_blocks);
p('Full Blocks ', l_full_blocks);
ELSE
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;
-- and then the unused space API call to get the rest of the
-- information
dbms_space.unused_space(segment_owner => p_owner,
segment_name => p_segname,
segment_type => p_type,
partition_name => p_partition,
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);
p('Total Blocks', l_total_blocks);
p('Total Bytes', l_total_bytes);
p('Total MBytes', trunc(l_total_bytes / 1024 / 1024));
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);
END;
7、快捷參考
有關性能優化請參考
有關ORACLE體系結構請參考
Oracle聯機重作日誌文件(ONLINE LOG FILE)
Oracle實例和Oracle數據庫(Oracle體系結構)
有關閃回特性請參考
Oracle閃回特性(FLASHBACK DATABASE)
Oracle閃回特性(FLASHBACK DROP & RECYCLEBIN)
Oracle閃回特性(Flashback Query、FlashbackTable)
Oracle閃回特性(Flashback Version、Flashback Transaction)
有關基於用戶管理的備份和備份恢復的概念請參考
Oracle基於用戶管理恢復的處理(詳細描述了介質恢復及其處理)
有關RMAN的備份恢復與管理請參考
RMAN 備份路徑困惑(使用plus archivelog時)
有關ORACLE故障請參考
對參數FAST_START_MTTR_TARGET= 0 的誤解及設定
有關ASM請參考
有關SQL/PLSQL請參考
SQL 基礎--> 集合運算(UNION與UNION ALL)
SQL 基礎--> 層次化查詢(STARTBY ... CONNECT BY PRIOR)
SQL 基礎--> ROLLUP與CUBE運算符實現數據彙總
有關ORACLE其它特性
使用OEM,SQL*Plus,iSQL*Plus 管理Oracle實例
日誌記錄模式(LOGGING、FORCE LOGGING 、NOLOGGING)
使用外部表管理Oracle 告警日誌(ALAERT_$SID.LOG)
簇表及簇表管理(Index clustered tables)
ORACLE_SID、DB_NAME、INSTANCE_NAME、DB_DOMIAN、GLOBAL_NAME