您的位置:首页 > 其它

批量自动_分析和处理_高水位的表格

2013-10-17 12:51 176 查看
发布在Itpub的,现在转过来这里。主要是在这个博客记录一些重要的脚本~

脚本目的:

主要的目的是整理磁盘碎片。在EBS里面有N多的接口表,或者有一些特殊的表格,经常Insert数据之后又Delete掉的。时间长之后,肯定会产生磁盘碎片,会导致高水位而带来的服务器效能的问题。换句话说这个优化就是清理系统使用过程中所产生的磁盘碎片。

高水位导致浪费磁盘空间之余,查询Table速度又慢,因为可能导致索引查询有问题。

所以,如何自动批量处理这部分的表格是我们遇到的问题。

处理对象:

处理的对象主要是DML(更新或者删除)频繁的临时表,特别是一堆接口表。

处理过程:

根据相关资料,整理了一个可以批量分析表格的是否高水位,然后自动用shrink space处理表格的脚本。

在10G数据库通过测试。

-----------------

注意:1 如果哪位兄台有兴趣使用这个脚本,强烈建议一定要先了解这个代码的处理逻辑,再选择是否使用。

2 鉴于个人的水平限制,如果脚本有什么误处理的地方,也请各位DBA高手斧正。。。

3 所有批量处理数据的DDL脚本必须是在系统空闲的时候执行!最好是停机备份之后再执行。如果在系统繁忙的时候做,会造成大量的等待,从而可能出现服务器瘫痪等问题。切记。

/*

--批量自动清理表空间的脚本

--2013.10.9 Create by sam.t

--逻辑:

处理对象:表(暂不处理分区表)和对应表的索引。

对于总块超过特定块数的(这里有个假设表格都是在最近1周内或者1个月内有分析过的。)

对特定的设定OWNER,再设定:存在空闲的块超过本身块的10%的,或者总的空闲块数量超过500个的。

就对应的表格立刻做:Shrink Segment的动作。如果表格存在索引,那索引也做Rebuild的动作。

*/

---建立日志表格:

CREATE TABLE XYG.XYG_DBA_SHRINK_TABLE_LOG

(BATCH_ID NUMBER

,OWNER VARCHAR2 (30 Byte)

,TABLE_NAME VARCHAR2 (30 Byte)

,BLOCKS NUMBER

,FREE_BLOCKS NUMBER

,SHRINK_BLOCKS NUMBER

,SHRINK_FLAG VARCHAR2(1) DEFAULT 'N' NOT NULL

,CREATED_BY NUMBER DEFAULT -1 NOT NULL --创建者

,CREATION_DATE DATE DEFAULT SYSDATE NOT NULL --创建日期

);

---这个SQL可以看到整理之后压缩了多少数据块,对应多大空间(MB)。注意,我这里一个数据块是8KB的空间。

SELECT SUM(SHRINK_BLOCKS)*8/1024 MB

FROM XYG.XYG_DBA_SHRINK_TABLE_LOG

WHERE SHRINK_FLAG = 'Y';

SELECT A.* FROM XYG.XYG_DBA_SHRINK_TABLE_LOG A WHERE CREATED_BY = -2 AND SHRINK_FLAG = 'Y'

SELECT SUM(SHRINK_BLOCKS)*8/1024 MB FROM XYG.XYG_DBA_SHRINK_TABLE_LOG A WHERE CREATED_BY = -2 AND SHRINK_FLAG = 'Y'

----------------主处理脚本:

DECLARE

L_OWNER VARCHAR2(10);--表格的Owner。

L_SHRINK_TABLE VARCHAR2(50);

L_TABLE_BLOCKS NUMBER;--总设定的要处理的表格最小块数。

L_FREE_RATE NUMBER;--总设定的比例.为空则表示不对此做限制。

L_FREE_BLOCKS NUMBER;---总设定的空闲块数。为空则表示不对此做限制。

---

L_OWNER1 VARCHAR2(10);--特定处理的表格的Owner1。

L_OWNER1_FREE_RATE NUMBER;--对应Owner1的设定的比例.为空则表示不对此做限制。

L_OWNER1_FREE_BLOCKS NUMBER;---对应的Owner1空闲块数。为空则表示不对此做限制。

---下面雷同,可以特殊4个Owner的处理。

L_OWNER2 VARCHAR2(10);

L_OWNER2_FREE_RATE NUMBER;

L_OWNER2_FREE_BLOCKS NUMBER;

L_OWNER3 VARCHAR2(10);

L_OWNER3_FREE_RATE NUMBER;

L_OWNER3_FREE_BLOCKS NUMBER;

L_OWNER4 VARCHAR2(10);

L_OWNER4_FREE_RATE NUMBER;

L_OWNER4_FREE_BLOCKS NUMBER;

--

L_FACT_FREE_RATE NUMBER;

L_FACT_FREE_BLOCKS NUMBER;

L_DEBUG_MODE BOOLEAN := FALSE;

L_ANALY_FREE_BLOCKS NUMBER;

L_ANALY_TABLE BOOLEAN := FALSE;

L_BATCH_ID NUMBER;

L_SHRINK_FLAG VARCHAR2(1);

L_SOURCE_TABLE_BLOCKS NUMBER;--原来的块数

L_SHRINK_TABLE_BLOCKS NUMBER;--整理碎片之后的收缩的块数

L_TOTAL_SHRINK_MB NUMBER;

---分析表格的空间用到的参数

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;

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;

----

CURSOR CUR_TABLES IS

SELECT OWNER,TABLE_NAME,BLOCKS,NUM_ROWS,ROW_MOVEMENT

FROM ALL_TABLES

WHERE 1=1

AND OWNER NOT IN ('SYS', 'SYSTEM')

AND TABLE_NAME NOT LIKE '%$%'

AND TEMPORARY = 'N'

AND PARTITIONED = 'NO'

AND BLOCKS > 0

AND (TABLE_NAME LIKE L_SHRINK_TABLE OR L_SHRINK_TABLE IS NULL)

AND (OWNER = L_OWNER OR L_OWNER IS NULL)

AND BLOCKS > L_TABLE_BLOCKS

AND NOT EXISTS(

SELECT 1 FROM XYG.XYG_DBA_SHRINK_TABLE_LOG XDT

WHERE XDT.OWNER = ALL_TABLES.OWNER

AND XDT.TABLE_NAME=ALL_TABLES.TABLE_NAME

AND XDT.SHRINK_FLAG <> 'E'

AND XDT.BATCH_ID = L_BATCH_ID)

ORDER BY OWNER,BLOCKS DESC;

procedure DEBUG_OUT( p_label in varchar2, p_num in number DEFAULT NULL )

is

begin

IF p_num IS NULL THEN

dbms_output.put_line( p_label);

ELSE

dbms_output.put_line( rpad(p_label,40,'.') ||p_num );

END IF;

end;

BEGIN

---输入的参数

--L_OWNER := 'XYG';

--L_SHRINK_TABLE := '%MESSAGE%';

L_TABLE_BLOCKS := 1000;

--默认的限制条件

L_FREE_RATE := 40;--40%以上的空闲空间的才考虑整理

L_FREE_BLOCKS := 1000;

L_DEBUG_MODE := FALSE;--TRUE;

L_BATCH_ID := 1;

---

L_OWNER1 := 'XYG';

L_OWNER1_FREE_RATE := 10;

L_OWNER1_FREE_BLOCKS := 100;

-----------------------

L_TOTAL_SHRINK_MB := 0;

L_SHRINK_FLAG := 'N';

--L_ANALY_TABLE := TRUE;

dbms_output.ENABLE(1000000);

DBMS_OUTPUT.PUT_LINE('---处理日期:'||TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS'));

---开始处理。

FOR REC_TABLES IN CUR_TABLES LOOP

L_ANALY_FREE_BLOCKS := 0;

L_SHRINK_FLAG := 'N';

L_SHRINK_TABLE_BLOCKS := 0;

---分析表的块的空闲率

dbms_space.space_usage(

segment_owner => REC_TABLES.owner ,

segment_name => REC_TABLES.TABLE_NAME ,

segment_type => 'TABLE' ,

unformatted_blocks => l_unformatted_blocks ,

unformatted_bytes => l_unformatted_bytes,

fs1_blocks => l_fs1_blocks,

fs1_bytes => l_fs1_bytes ,

fs2_blocks => l_fs2_blocks,

fs2_bytes => l_fs2_bytes,

fs3_blocks => l_fs3_blocks ,

fs3_bytes => l_fs3_bytes,

fs4_blocks => l_fs4_blocks,

fs4_bytes => l_fs4_bytes,

full_blocks => l_full_blocks,

full_bytes => l_full_bytes);

IF L_DEBUG_MODE THEN

DEBUG_OUT(rpad(' ',50,'*'));

DEBUG_OUT('Show Space Segment:'||REC_TABLES.owner ||'.'||REC_TABLES.TABLE_NAME);

DEBUG_OUT('The segment is analyzed');

DEBUG_OUT( '0% -- 25% free space blocks', l_fs1_blocks);

DEBUG_OUT( '0% -- 25% free space bytes', l_fs1_bytes);

DEBUG_OUT( '25% -- 50% free space blocks', l_fs2_blocks);

DEBUG_OUT( '25% -- 50% free space bytes', l_fs2_bytes);

DEBUG_OUT( '50% -- 75% free space blocks', l_fs3_blocks);

DEBUG_OUT( '50% -- 75% free space bytes', l_fs3_bytes);

DEBUG_OUT( '75% -- 100% free space blocks', l_fs4_blocks);

DEBUG_OUT( '75% -- 100% free space bytes', l_fs4_bytes);

DEBUG_OUT( 'Unused Blocks', l_unformatted_blocks );

DEBUG_OUT( 'Unused Bytes', l_unformatted_bytes );

DEBUG_OUT( 'Total Blocks', l_full_blocks);

DEBUG_OUT( 'Total bytes', l_full_bytes);

END IF;

L_FACT_FREE_RATE := CASE WHEN REC_TABLES.owner = L_OWNER1 THEN L_OWNER1_FREE_RATE

WHEN REC_TABLES.owner = L_OWNER2 THEN L_OWNER2_FREE_RATE

WHEN REC_TABLES.owner = L_OWNER3 THEN L_OWNER3_FREE_RATE

WHEN REC_TABLES.owner = L_OWNER4 THEN L_OWNER4_FREE_RATE

ELSE L_FREE_RATE

END;

L_FACT_FREE_BLOCKS := CASE WHEN REC_TABLES.owner = L_OWNER1 THEN L_OWNER1_FREE_BLOCKS

WHEN REC_TABLES.owner = L_OWNER2 THEN L_OWNER2_FREE_BLOCKS

WHEN REC_TABLES.owner = L_OWNER3 THEN L_OWNER3_FREE_BLOCKS

WHEN REC_TABLES.owner = L_OWNER4 THEN L_OWNER4_FREE_BLOCKS

ELSE L_FREE_BLOCKS

END;

IF L_DEBUG_MODE THEN

DEBUG_OUT('L_FACT_FREE_RATE:'||L_FACT_FREE_RATE);

DEBUG_OUT('L_FACT_FREE_BLOCKS:'||L_FACT_FREE_BLOCKS);

END IF;

L_ANALY_FREE_BLOCKS := (NVL(l_fs1_blocks,0)+NVL(l_fs2_blocks,0)+NVL(l_fs3_blocks,0)+NVL(l_fs4_blocks,0));

SELECT SUM(BLOCKS)

INTO L_SOURCE_TABLE_BLOCKS

FROM dba_segments

WHERE OWNER = REC_TABLES.owner AND SEGMENT_NAME = REC_TABLES.TABLE_NAME AND SEGMENT_TYPE = 'TABLE';

IF L_DEBUG_MODE THEN

DEBUG_OUT('表格总块数:'||L_SOURCE_TABLE_BLOCKS||' 存在空闲的块数:'||L_ANALY_FREE_BLOCKS);

END IF;

IF (L_ANALY_FREE_BLOCKS/L_SOURCE_TABLE_BLOCKS)*100 >=L_FACT_FREE_RATE

OR L_ANALY_FREE_BLOCKS>= L_FACT_FREE_BLOCKS THEN

DEBUG_OUT('处理表格:'||REC_TABLES.owner ||'.'||REC_TABLES.TABLE_NAME);

L_SHRINK_FLAG := 'Y';

IF REC_TABLES.ROW_MOVEMENT = 'DISABLED' THEN

execute immediate 'alter table '||REC_TABLES.owner||'.'||REC_TABLES.TABLE_NAME||' enable row movement';

END IF;

BEGIN

execute immediate 'alter table '||REC_TABLES.owner||'.'||REC_TABLES.TABLE_NAME||' shrink space';

EXCEPTION

WHEN OTHERS THEN

DEBUG_OUT('处理表格出现异常错误,信息:'||SQLCODE ||'.'||SQLERRM);

L_SHRINK_FLAG := 'E';

END;

IF REC_TABLES.ROW_MOVEMENT = 'DISABLED' THEN

execute immediate 'alter table '||REC_TABLES.owner||'.'||REC_TABLES.TABLE_NAME||' disable row movement';

END IF;

COMMIT;

---下面的索引也全部重建。必须的。前提是已经成功有对表做过修整。

FOR REC_INDEX IN (

SELECT AI.OWNER,AI.INDEX_NAME

FROM all_indexes AI

WHERE OWNER NOT IN ('SYS', 'SYSTEM')

AND AI.INDEX_NAME NOT LIKE '%$%'

AND AI.TABLE_OWNER = REC_TABLES.owner

AND AI.TABLE_NAME = REC_TABLES.TABLE_NAME

AND L_SHRINK_FLAG = 'Y'

ORDER BY 2) LOOP

IF L_DEBUG_MODE THEN

DEBUG_OUT('重建索引:'||REC_INDEX.owner||'.'||REC_INDEX.INDEX_NAME);

END IF;

BEGIN

execute immediate 'ALTER INDEX '||REC_INDEX.owner||'.'||REC_INDEX.INDEX_NAME||' REBUILD ONLINE';

EXCEPTION

WHEN OTHERS THEN

DEBUG_OUT('重建表格索引出现异常错误,信息:'||SQLCODE ||'.'||SQLERRM);

--可能是表空间不足,那就不需要再往下处理了。直接退出

exit;

END;

/*

--重新分析索引

begin

dbms_stats.gather_index_stats(ownname => REC_INDEX.owner,

indname => REC_INDEX.INDEX_NAME,

estimate_percent => 33

);

end;*/

END LOOP;

--表格重新分析!

---如果需要重新分析表格,则执行。主要是速度的问题。如果重新分析表格和索引,速度会很慢。可以根据日志表格来统一执行也行。

IF L_ANALY_TABLE AND L_SHRINK_FLAG = 'Y' THEN

BEGIN

DBMS_STATS.GATHER_TABLE_STATS (

OWNNAME => REC_TABLES.OWNER

,TABNAME => REC_TABLES.TABLE_NAME

,METHOD_OPT => 'FOR ALL COLUMNS SIZE 1' --不统计直方图的信息 --'FOR ALL INDEXED COLUMNS SIZE AUTO'

,CASCADE => TRUE ---TRUE就是分析索引的意思。

,ESTIMATE_PERCENT => 33--DBMS_STATS.AUTO_SAMPLE_SIZE

);

EXCEPTION

WHEN OTHERS THEN

DBMS_OUTPUT.PUT_LINE (REC_TABLES.TABLE_NAME || '-' || SQLERRM);

END;

END IF;

IF L_SHRINK_FLAG = 'Y' THEN

SELECT L_SOURCE_TABLE_BLOCKS - SUM(BLOCKS)

INTO L_SHRINK_TABLE_BLOCKS

FROM dba_segments

WHERE OWNER = REC_TABLES.owner AND SEGMENT_NAME = REC_TABLES.TABLE_NAME AND SEGMENT_TYPE = 'TABLE';

--换算为MB单位,注意这里每一个块对应的大小是数据库的设定,可以通过v$parameter查询。我这里设定1块=8kb

L_TOTAL_SHRINK_MB := L_TOTAL_SHRINK_MB + L_SHRINK_TABLE_BLOCKS*8/1024;

END IF;

IF L_DEBUG_MODE THEN

DEBUG_OUT('---整理磁盘碎片之后收缩的块数-空间'||L_SHRINK_TABLE_BLOCKS||'--'||ROUND(L_SHRINK_TABLE_BLOCKS*8/1024,4)||')---');

END IF;

END IF;

---塞入临时的表格。

INSERT INTO XYG.XYG_DBA_SHRINK_TABLE_LOG

(BATCH_ID,OWNER,TABLE_NAME,BLOCKS,FREE_BLOCKS,SHRINK_BLOCKS,SHRINK_FLAG,CREATED_BY)

SELECT L_BATCH_ID,REC_TABLES.owner,REC_TABLES.TABLE_NAME

,L_SOURCE_TABLE_BLOCKS,L_ANALY_FREE_BLOCKS,L_SHRINK_TABLE_BLOCKS,L_SHRINK_FLAG,-2

FROM DUAL;

END LOOP;

DEBUG_OUT('本次整理磁盘碎片之后共收缩的空间(MB)'||L_TOTAL_SHRINK_MB||')');

COMMIT;

END;

------我自己打处理步骤:

预计每半年做一次。每次是需要分批做。

第一批:

1 所有的XYG开头的表格都要处理一次。

L_OWNER := 'XYG'

--L_SHRINK_TABLE := 'XYG_ASSEMBLE_BOX';

L_TABLE_BLOCKS := 100;

--默认的限制条件

L_FREE_RATE := 50;

L_FREE_BLOCKS := 2000;

L_DEBUG_MODE := TRUE;

L_BATCH_ID := 1;

---

L_OWNER1 := 'XYG';

L_OWNER1_FREE_RATE := 10;

L_OWNER1_FREE_BLOCKS := 100;

本次整理磁盘碎片之后共收缩的空间(MB)305)

2 系统所有的接口表,肯定是很多很慢的:

--因为这个语句不可以整理含有函数索引的表的碎片,所以在做之前要删掉索引。再重建。

DROP INDEX AR.RA_INTERFACE_LINES_N7;

CREATE INDEX AR.RA_INTERFACE_LINES_N7 ON AR.RA_INTERFACE_LINES_ALL

(NVL("INTERFACE_STATUS",'SAMT'), SALES_ORDER, CREATION_DATE)

LOGGING

TABLESPACE APPS_TS_INTERFACE

PCTFREE 10

INITRANS 11

MAXTRANS 255

STORAGE (

INITIAL 128K

NEXT 128K

MINEXTENTS 1

MAXEXTENTS UNLIMITED

PCTINCREASE 0

BUFFER_POOL DEFAULT

)

NOPARALLEL;

---输入的参数

--L_OWNER := 'XYG';

L_SHRINK_TABLE := '%INTER%';

L_TABLE_BLOCKS := 0;

--默认的限制条件

L_FREE_RATE := 10;

L_FREE_BLOCKS := 100;

L_DEBUG_MODE := TRUE;

L_BATCH_ID := 1;

---

L_OWNER1 := 'XYG';

L_OWNER1_FREE_RATE := 10;

L_OWNER1_FREE_BLOCKS := 100;

本次整理磁盘碎片之后共收缩的空间(MB)425.5)

3 系统所有的消息表,可能是临时的作用。

---输入的参数

--L_OWNER := 'XYG';

L_SHRINK_TABLE := '%MESSAGE%';

L_TABLE_BLOCKS := 0;

--默认的限制条件

L_FREE_RATE := 10;

L_FREE_BLOCKS := 100;

L_DEBUG_MODE := TRUE;

L_BATCH_ID := 1;

---

L_OWNER1 := 'XYG';

L_OWNER1_FREE_RATE := 10;

L_OWNER1_FREE_BLOCKS := 100;

4 系统所有的临时表

L_SHRINK_TABLE := '%TEMP%';

本次整理磁盘碎片之后共收缩的空间(MB)25.25)

5 系统所有的可能存在问题的表格--慎重!

正式环境可以不做这个步骤。

---输入的参数

--L_OWNER := 'XYG';

--L_SHRINK_TABLE := '%MESSAGE%';

L_TABLE_BLOCKS := 1000;

--默认的限制条件

L_FREE_RATE := 40;--40%以上的空闲空间的才考虑整理

L_FREE_BLOCKS := 1000;

L_DEBUG_MODE := FALSE;--TRUE;

L_BATCH_ID := 1;

---

L_OWNER1 := 'XYG';

L_OWNER1_FREE_RATE := 10;

L_OWNER1_FREE_BLOCKS := 100;

本次整理磁盘碎片之后共收缩的空间(MB)844.375)

,'WF_DEFERRED'

,'FND_CRM_HISTORY'

,'FND_CONC_REQUEST_ARGUMENTS'

,'FND_RUN_REQ_PP_ACTIONS'

,'FND_CP_GSM_IPC_AQTBL'

,'ICX_TRANSACTIONS'

,'ICX_SESSIONS'

,'ICX_SESSION_ATTRIBUTES'

,'MTL_CATALOG_SEARCH_ITEMS'

,'OE_PROCESSING_MSGS'

,'OE_PROCESSING_MSGS_TL'

,'PO_EMPLOYEE_HIERARCHIES_ALL'

,'WSH_EXCEPTIONS'

,'XLA_AAD_LOADER_DEFNS_T'

,'FND_CP_GSM_OPP_AQTBL'

,'AD_SNAPSHOT_BUGFIXES'

,'FND_RUN_REQUESTS'

,'AD_TASK_TIMING'

,'FND_CONC_PP_ACTIONS'

,'FND_ENV_CONTEXT'

,'WF_JAVA_DEFERRED'

6 重点跟踪某些特定的大表。

主要是:FND_LOG_MESSAGES

------

备注:本文主要参考了文章:http://www.itpub.net/thread-1314057-1-1.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: