1 目的
指導oracle DBA根據不同的場景,快速、正確地完成段碎片整理
2 執行人
Oracle dba
3 執行場景
- 常規場景:數據歸檔
- 非常規場景:系統對某個表執行頻繁insert,delete,造成大量的碎片。
4 回收碎片
回收碎片,一般可以分爲兩種方式:
- 在線回收,不會造成業務中斷,執行時間長。
- 離線回收,需要中斷業務,執行時間長快,需兩倍的空間。
4.1 在線回收
4.1.1使用shrink space cascade方式
- 點評:當表大小在4G以上時間都會很久,約20-30分鐘.以及會消耗UNDO空間,對於大表 往往會由於UNDO表空間不足而收縮失敗。
- 代碼如下:
alter table T1 enable row movement;
alter table T1 shrink space cascade;
alter table T1 disable row movement;
4.1.2 使用在線重定義方式
- 過程複雜,代碼構建時間長。
- 代碼如下:
/*
title: 測試在線重定義
step:
1. 生成master的測試表qqmaster(包括所有索引,主鍵)
2.模擬進行歸檔
3.執行在線重定義
4.執行在線重定義時,模擬有數據插到qqmaster,頻率是每秒100行記錄。
*/
drop TABLE CBS.QQMASTER;
drop table CBS.QQMATER_TMP;
create table CBS.QQMASTER tablespace cbs as select * from cbs.master;
--select min(so_period) from CBS.SO_QQMASTER;
--刪除2013年所有回單數據
declare
begin
for period in 201301 .. 201312 loop
execute immediate 'delete CBS.QQMASTER where so_period =:1' using to_char(period);
commit;
end loop;
end;
/
--檢查能回收多少空間
--object_type :TABLESPACE TABLE INDEX
-- attr1: tablespacename owner owner
--atrr2: null table_name index_name
begin
declare
name varchar2(100);
descr varchar2(500);
obj_id number;
id number;
begin
name:='dbahqq20170823003';
descr:='Segment Advisor';
dbms_advisor.create_task (
advisor_name => 'Segment Advisor',
task_id => id,
task_name => name,
task_desc => descr);
dbms_advisor.create_object (
task_name => name,
object_type => 'TABLE',
attr1 => 'CBS',
attr2 => 'QQMASTER',
attr3 => NULL,
attr4 => NULL,
attr5 => NULL,
object_id => obj_id);
dbms_advisor.set_task_parameter(
task_name => name,
parameter => 'recommend_all',
value => 'TRUE');
dbms_advisor.execute_task(name);
end;
end;
select * from SYS.DBA_ADVISOR_FINDINGS where task_name='hqq20170822001';
select a.*,round(recycle_space/allocate_space,4) from (
select a.message,a.more_info,b.type,b.attr2 ,b.attr1
,substr(more_info,6,instr(more_info,': 已用空間:',1)-6)/1024/1024 allocate_space,
substr(more_info,instr(more_info,': 已用空間:',1)+7,instr(more_info,': 可回收空間:',1)-instr(more_info,': 已用空間:',1)-7)/1024/1024 used_space
,(substr(more_info,6,instr(more_info,': 已用空間:',1)-6)-substr(more_info,instr(more_info,': 已用空間:',1)+7,instr(more_info,': 可回收空間:',1)-instr(more_info,': 已用空間:',1)-7))/1024/1024 recycle_space
from DBA_ADVISOR_FINDINGS a,DBA_ADVISOR_OBJECTS b
where a.owner=b.owner and a.owner='SYS' and (message like '%收縮%' OR message like '%壓縮%') and a.object_id=b.object_id and a.task_name='hqq20170823003' and a.task_name=b.task_name
order by recycle_space desc) a;
--開始在線重定義
--檢查在線重定義
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('CBS', 'QQMASTER', DBMS_REDEFINITION.CONS_USE_PK);
--創建中間表,用於段空間的置換。
CREATE TABLE CBS.SO_QQMASTER_TMP as select * from cbs.qqmaster where rownum<1;
EXEC SYS.DBMS_REDEFINITION.START_REDEF_TABLE('CBS','QQMASTER','QQMASTER_TMP');
select * from cbs.SO_QQMASTER_TMP;
--模擬一邊插入數據,一邊在finisih
declare
qq_row SO_MASTER%rowtype;
begin
for qq_row in (select * from MASTER where so_period='201301'and rownum<=100) loop
--execute immediate 'insert into QQMASTER values (:1)' using qq_row;
insert into QQMASTER values qq_row;
SYS.DBMS_LOCK.SLEEP(1/10);
commit;
end loop;
end;
/
--將原表的依賴複製到中間表中。
DECLARE
error_count pls_integer := 0;
BEGIN
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('hqq', 'QQMASTER', 'QQMASTER_TMP', dbms_redefinition.cons_orig_params, TRUE,TRUE,TRUE,FALSE, error_count);
DBMS_OUTPUT.PUT_LINE('errors := ' || TO_CHAR(error_count));
END;
/
--同步重新重定義
EXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE('HQQ','QQMASTER','QQMASTER_TMP');
--完成重定義
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('HQQ','QQMASTER','QQMASTER_TMP');
--檢查數據
select count(*) from HQQ.QQMASTER;
select count(*) from HQQ.QQMASTER_TMP;
select count(*) from HQQ.QQMASTER_TMP where so_period='201302';
select count(*) from HQQ.QQMASTER where so_period='201302';
select * from dba_segments where segment_name='QQMASTER_TMP';
離線回收
- 點評:過程簡單,速度快,用時短,業務中斷。
- 代碼如下:
alter table T1 move ;--不加tablespace就是要move到原表空間中,所以表空間一定要足夠的容量。
重建表T1的索引。
alter index XXX rebuild parallel 8;
alter index xxx noparallel;
備註
-- -----------------------------------------------------------------------------------
-- File Name : https://oracle-base.com/dba/10g/segment_advisor.sql
-- Author : Tim Hall
-- Description : Displays segment advice for the specified segment.
-- Requirements : Access to the DBMS_ADVISOR package.
-- Call Syntax : Object-type = "tablespace":
-- @segment_advisor.sql tablespace (tablespace-name) null
-- Object-type = "table" or "index":
-- @segment_advisor.sql (object-type) (object-owner) (object-name)
-- Last Modified: 08-APR-2005
-- -----------------------------------------------------------------------------------
SET SERVEROUTPUT ON SIZE 1000000
SET LINESIZE 200
SET VERIFY OFF
DECLARE
l_object_id NUMBER;
l_task_name VARCHAR2(32767) := 'SEGMENT_ADVISOR_TASK';
l_object_type VARCHAR2(32767) := UPPER('&1');
l_attr1 VARCHAR2(32767) := UPPER('&2');
l_attr2 VARCHAR2(32767) := UPPER('&3');
BEGIN
IF l_attr2 = 'NULL' THEN
l_attr2 := NULL;
END IF;
DBMS_ADVISOR.create_task (
advisor_name => 'Segment Advisor',
task_name => l_task_name);
DBMS_ADVISOR.create_object (
task_name => l_task_name,
object_type => l_object_type,
attr1 => l_attr1,
attr2 => l_attr2,
attr3 => NULL,
attr4 => 'null',
attr5 => NULL,
object_id => l_object_id);
DBMS_ADVISOR.set_task_parameter (
task_name => l_task_name,
parameter => 'RECOMMEND_ALL',
value => 'TRUE');
DBMS_ADVISOR.execute_task(task_name => l_task_name);
FOR cur_rec IN (SELECT f.impact,
o.type,
o.attr1,
o.attr2,
f.message,
f.more_info
FROM dba_advisor_findings f
JOIN dba_advisor_objects o ON f.object_id = o.object_id AND f.task_name = o.task_name
WHERE f.task_name = l_task_name
ORDER BY f.impact DESC)
LOOP
DBMS_OUTPUT.put_line('..');
DBMS_OUTPUT.put_line('Type : ' || cur_rec.type);
DBMS_OUTPUT.put_line('Attr1 : ' || cur_rec.attr1);
DBMS_OUTPUT.put_line('Attr2 : ' || cur_rec.attr2);
DBMS_OUTPUT.put_line('Message : ' || cur_rec.message);
DBMS_OUTPUT.put_line('More info : ' || cur_rec.more_info);
END LOOP;
DBMS_ADVISOR.delete_task(task_name => l_task_name);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line('Error : ' || DBMS_UTILITY.format_error_backtrace);
DBMS_ADVISOR.delete_task(task_name => l_task_name);
END;
/