Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103559388
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: Oracle

2008-03-31 12:52:00

来源:赛迪网    作者:小桥

Oracle 9i:

首先,我们需要执行以下的sql,创建包:

CREATE OR REPLACE PACKAGE statspack_admin AS

PROCEDURE purge_older_than_days 
(days IN INTEGER, area_size IN INTEGER DEFAULT NULL);


/*
-- submit a job to run every day at 3am 
deleting snaps older than 30 days
-- specifying 50Mb for PGA.

DECLARE
j BINARY_INTEGER;
BEGIN
DBMS_JOB.SUBMIT(j, 'statspack_admin.purge_older_than_days(30, 52428800);', 
TRUNC(SYSDATE)+(3/24), 'TRUNC(SYSDATE)+1+(3/24)' );
COMMIT;
END;

*/

PROCEDURE purge (lo_snap IN NUMBER, hi_snap IN NUMBER, 
area_size IN INTEGER DEFAULT NULL);

PROCEDURE move_tablespace 
(tablespace_name IN VARCHAR2, window_in_hours IN NUMBER);

END statspack_admin;
/


CREATE OR REPLACE PACKAGE BODY statspack_admin AS

on_9i BOOLEAN := FALSE;
dbversion VARCHAR2(512);
dbcompat VARCHAR2(512);

PROCEDURE purge (lo_snap IN NUMBER, hi_snap IN NUMBER, 
area_size IN INTEGER DEFAULT NULL)
IS

dbid v$database.dbid%TYPE;
inst_num v$instance.instance_number%TYPE;
inst_name v$instance.instance_name%TYPE;
db_name v$database.name%TYPE;
btime DATE;
etime DATE;

BEGIN

SELECT 
d.dbid AS dbid, i.instance_number AS inst_num, 
i.instance_name AS inst_name, d.name AS db_name 
INTO 
dbid, inst_num, inst_name, db_name
FROM 
v$database d, v$instance i;

select snap_time
into btime
from stats$snapshot b
where b.snap_id = (SELECT MIN(x.snap_id) 
FROM stats$snapshot x WHERE x.snap_id >= lo_snap) 
and b.dbid = dbid
and b.instance_number = inst_num;

select snap_time 
into etime
from stats$snapshot e
where e.snap_id = (SELECT MAX(x.snap_id) 
FROM stats$snapshot x WHERE x.snap_id <= hi_snap) 
and e.dbid = dbid
and e.instance_number = inst_num;

IF on_9i AND area_size IS NOT NULL 
THEN
EXECUTE IMMEDIATE 'alter session set workarea_size_policy=MANUAL';
EXECUTE IMMEDIATE 'alter session set hash_area_size='||TO_CHAR(area_size);
EXECUTE IMMEDIATE 'alter session set sort_area_size='||TO_CHAR(area_size);
ELSIF area_size IS NOT NULL THEN
EXECUTE IMMEDIATE 'alter session set hash_area_size='||TO_CHAR(area_size);
EXECUTE IMMEDIATE 'alter session set sort_area_size='||TO_CHAR(area_size);
END IF;

delete from stats$snapshot
where instance_number = inst_num
and dbid = dbid
and snap_id between lo_snap and hi_snap;

/*-- Delete any dangling SQLtext 
-- The following statement deletes any dangling SQL statements which
-- are no longer referred to by ANY snapshots. This statment has been
-- commented out as it can be very resource intensive. 
--*/
delete --+ index_ffs(st) 
from stats$sqltext st
where (hash_value, text_subset) not in
(select --+ hash_aj full(ss) no_expand 
hash_value, text_subset
from stats$sql_summary ss
where ( ( snap_id < lo_snap
or snap_id > hi_snap
)
and dbid = dbid
and instance_number = inst_num
)
or ( dbid != dbid
or instance_number != inst_num)
);

-- Adding an optional STATS$SEG_STAT_OBJ delete statement
delete --+ index_ffs(sso)
from stats$seg_stat_obj sso
where (dbid, dataobj#, obj#) not in
(select --+ hash_aj full(ss) no_expand
dbid, dataobj#, obj#
from stats$seg_stat ss
where ( ( snap_id < lo_snap
or snap_id > hi_snap
)
and dbid = dbid
and instance_number = inst_num
)
or ( dbid != dbid
or instance_number != inst_num)
);

/* Delete any undostat rows that cover the snap times */
delete from stats$undostat us
where dbid = dbid
and instance_number = inst_num
and begin_time < btime
and end_time > etime;

/* Delete any dangling database 
nstance rows for that startup time */
delete from stats$database_instance di
where instance_number = inst_num
and dbid = dbid
and not exists (select 1
from stats$snapshot s
where s.dbid = di.dbid
and s.instance_number = di.instance_number
and s.startup_time = di.startup_time);

/* Delete any dangling statspack parameter 
rows for the database instance */
delete from stats$statspack_parameter sp
where instance_number = inst_num
and dbid = dbid
and not exists (select 1
from stats$snapshot s
where s.dbid = sp.dbid
and s.instance_number = sp.instance_number);

COMMIT;


END purge;

/* procedure to move tablespaces */

PROCEDURE move_tablespace 
(tablespace_name IN VARCHAR2, window_in_hours IN NUMBER)
IS
ts DATE := SYSDATE; 
te DATE := ts + (window_in_hours/24);
BEGIN

-- do the tables that haven't been rebuilt recently first
FOR t IN (SELECT object_name AS table_name 
FROM user_objects WHERE object_type = 'TABLE' 
ORDER BY last_ddl_time ASC) LOOP

EXECUTE IMMEDIATE 'ALTER TABLE '
||t.table_name||' MOVE TABLESPACE '||tablespace_name;

-- now immediately rebuild the indexes
-- I could use dbms_job to do this 
asynchronously, maybe in a future revision?
-- not using ONLINE because moving 
tables cannot be done ONLINE! 
-- maybe use dbms_redef in future version? 
FOR i IN (SELECT index_name FROM user_indexes 
WHERE table_name = t.table_name) LOOP
EXECUTE IMMEDIATE 'ALTER INDEX '||i.index_name||' 
REBUILD TABLESPACE '||tablespace_name;
END LOOP;

IF SYSDATE > te THEN
EXIT;
END IF;

END LOOP;

EXCEPTION
WHEN OTHERS THEN
IF dbms_job.is_jobq THEN -- remove the 
job preventing nasty reruns outside the 
window but generating a trace file for the DBA
DBMS_JOB.REMOVE( NVL(SYS_CONTEXT('USERENV','BG_JOB_ID'),SYS_CONTEXT

('USERENV','FG_JOB_ID') ) );
COMMIT;
END IF; 
RAISE;

END move_tablespace;

/* purge records older than X days */
PROCEDURE purge_older_than_days (days IN INTEGER, 
area_size IN INTEGER DEFAULT NULL) 
IS

losnap stats$snapshot.SNAP_ID%TYPE;
hisnap stats$snapshot.SNAP_ID%TYPE;

BEGIN

SELECT
s.snap_id
INTO 
hisnap
FROM
stats$snapshot s
WHERE 
s.snap_id =
(
SELECT 
MAX(s.snap_id)
FROM 
stats$snapshot s
WHERE 
s.snap_time < TRUNC(SYSDATE)-days
);

SELECT
s.snap_id
INTO 
losnap 
FROM
stats$snapshot s
WHERE 
s.snap_id = (
SELECT
MIN(s.snap_id) 
FROM 
stats$snapshot s
WHERE 
s.snap_id <= hisnap -- in case the highest 
snap is the only one to delete
);

--DBMS_OUTPUT.PUT_LINE('Lo Snap: '||TO_CHAR(losnap));
--DBMS_OUTPUT.PUT_LINE('Hi Snap: '||TO_CHAR(hisnap));

purge (losnap, hisnap, area_size);

EXCEPTION 
WHEN NO_DATA_FOUND THEN
NULL; -- select into hisnap returned no rows, 
which means no snaps are older than days specified

END purge_older_than_days; 

BEGIN 

SYS.DBMS_UTILITY.DB_VERSION(dbversion, dbcompat);

IF TO_NUMBER(REPLACE(dbversion, '.')) 
>= 90000 THEN -- we are on a 9i DB 
on_9i := TRUE;
ELSE
on_9i := FALSE;
END IF; 

EXCEPTION
WHEN OTHERS THEN
on_9i := FALSE;

END statspack_admin;
/

2.然后再继续手工执行:

DECLARE
j BINARY_INTEGER;
BEGIN
DBMS_JOB.SUBMIT(j, 'statspack_admin.purge_older_than_days
(30, 52428800);', TRUNC(SYSDATE)+(3/24), 'TRUNC(SYSDATE)+1+(3/24)' );
COMMIT;
END;

Oracle 10g:

自带了此项功能:

10g has statspack.purge to do this, for example: 

exec statspack.purge(trunc(sysdate - 7), true)
阅读(397) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~