2017-08-22 DBA日記,段收縮

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;
/

發佈了73 篇原創文章 · 獲贊 6 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章