oracle database expert performance tuning buffer pools keep recycle sqlplus query TOAD system trigger plsql programming
Edward Stoever is your
DATABASE-EXPERT
Computer solutions for businesses of all sizes!
(818) 528-4111
 Home  Résumé  Articles  Portfolio  Contact  YouTube 
ORACLE - STATSPACK ADMINISTRATION
By Edward Stoever
I created the following package to make statspack maintanence automatic. We don't need snaps to accumulate beyond 10 days.
CREATE OR REPLACE PACKAGE statspack_admin
AS
/******************************************************************************
   NAME:       statspack_admin
   PURPOSE:    Administer statspack - This package will help make statspack
                                      administration automatic and easy.
                                      ©2004 - Edward Stoever
                                      
   REVISIONS:
   Ver        Date        Author           Description
   ---------  ----------  ---------------  ------------------------------------
   1.0        9/9/2004    Edward Stoever   1. Created this package.
******************************************************************************/
   PROCEDURE purge_old_snaps (days_ago NUMBER DEFAULT 10);

   PROCEDURE purge_once_per_day (days_ago NUMBER DEFAULT 10);

   PROCEDURE resubmit_snap_jobs (snaps_per_day NUMBER DEFAULT 12);
END statspack_admin;
/
CREATE OR REPLACE PACKAGE BODY statspack_admin
AS
/******************************************************************************
   NAME:       statspack_admin
   PURPOSE:    Administer statspack - This package will help make statspack
                                      administration automatic and easy.
                                      ©2004 - Edward Stoever
                                      
   REVISIONS:
   Ver        Date        Author           Description
   ---------  ----------  ---------------  ------------------------------------
   1.0        9/9/2004    Edward Stoever   1. Created this package body.
******************************************************************************/
   FUNCTION instance_number
      RETURN NUMBER
   IS
      inst   NUMBER;
   BEGIN
      SELECT instance_number
        INTO inst
        FROM v$instance;

      RETURN inst;
   EXCEPTION
      WHEN OTHERS
      THEN
         RETURN 1;
   END;

   FUNCTION today_at_1am
      RETURN DATE
   IS
      var_today_at_1am   DATE;
   BEGIN
      var_today_at_1am :=
         TO_DATE (TO_CHAR (SYSDATE, 'MM/DD/YYYY') || ' 1:00:00 AM',
                  'MM/DD/YYYY HH:MI:SS AM'
                 );
      RETURN var_today_at_1am;
   END;

   FUNCTION convert_days_ago (days_ago NUMBER)
      RETURN NUMBER
   IS
      xdays   NUMBER;
   BEGIN
      IF days_ago > 30
      THEN
         xdays := 30;
      ELSE
         xdays := FLOOR (ABS (days_ago));
      END IF;

      RETURN xdays;
   EXCEPTION
      WHEN OTHERS
      THEN
         RETURN 30;
   END;

   PROCEDURE purge_old_snaps (days_ago NUMBER DEFAULT 10)
   /*
   THIS PROCEDURE WAS DERIVED FROM $ORACLE_HOME/RDBMS/ADMIN/SPPURGE.SQL
   AND IS USED TO DELETE OLD SNAPS.
   IT CAN BE SUBMITTED AS A JOB VIA DBMS_JOB.
   */
   IS
      dbid          NUMBER;
      inst_num      NUMBER;
      inst_name     VARCHAR2 (20);
      db_name       VARCHAR2 (20);
      max_snap_id   NUMBER         := 0;
      btime         VARCHAR2 (100);
      etime         VARCHAR2 (100);
      xdays         NUMBER;
   BEGIN
      xdays := convert_days_ago (days_ago);

      SELECT d.dbid dbid, d.NAME db_name, i.instance_number inst_num,
             i.instance_name inst_name
        INTO dbid, db_name, inst_num,
             inst_name
        FROM v$database d, v$instance i
       WHERE ROWNUM = 1;

      --delete everything from xdays days ago!
      SELECT MAX (s.snap_id)
        INTO max_snap_id
        FROM stats$snapshot s
       WHERE s.dbid = dbid
         AND s.instance_number = inst_num
         AND s.snap_time < (SYSDATE - xdays);

      IF max_snap_id <> 0
      THEN
         SELECT TO_CHAR (snap_time, 'YYYYMMDD HH24:MI:SS')
           INTO btime
           FROM stats$snapshot b
          WHERE b.snap_id =
                       (SELECT MIN (s.snap_id)
                          FROM stats$snapshot s
                         WHERE s.dbid = dbid AND s.instance_number = inst_num)
            AND b.dbid = dbid
            AND b.instance_number = inst_num;

         SELECT TO_CHAR (snap_time, 'YYYYMMDD HH24:MI:SS')
           INTO etime
           FROM stats$snapshot e
          WHERE e.snap_id = max_snap_id
            AND e.dbid = dbid
            AND e.instance_number = inst_num;

         DELETE FROM stats$snapshot
               WHERE instance_number = inst_num
                 AND dbid = dbid
                 AND snap_id <= max_snap_id;

/*  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 < TO_DATE (btime, 'YYYYMMDD HH24:MI:SS')
                 AND end_time > TO_DATE (etime, 'YYYYMMDD HH24:MI:SS');

/*  Delete any dangling database instance 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 IF;
	  
	   EXCEPTION
      WHEN OTHERS
      THEN
         ROLLBACK;
   END purge_old_snaps;

   PROCEDURE purge_once_per_day (days_ago NUMBER DEFAULT 10)
   /* THIS WILL PURGE OLD SNAPS ONCE PER DAY AT 1:00 AM */
   IS
      CURSOR c_1
      IS
         SELECT job
           FROM user_jobs
          WHERE LOWER (TRIM (what)) LIKE '%purge_old_snaps%';

      var_purge_job   NUMBER;
      instno          NUMBER;
      jobno           NUMBER;
      x_days          NUMBER;
   BEGIN
      x_days := convert_days_ago (days_ago);

      OPEN c_1;

      LOOP
         FETCH c_1
          INTO var_purge_job;

         EXIT WHEN c_1%NOTFOUND;
         DBMS_JOB.remove (var_purge_job);
      END LOOP;

      CLOSE c_1;

      instno := instance_number;
      DBMS_JOB.submit (jobno,
                          'statspack_admin.purge_old_snaps('
                       || TO_CHAR (x_days)
                       || ');',
                       TRUNC (today_at_1am + 1, 'HH'),
                       'trunc(SYSDATE+1,''HH'')',
                       TRUE,
                       instno
                      );
      COMMIT;
   END purge_once_per_day;

   PROCEDURE resubmit_snap_jobs (snaps_per_day NUMBER DEFAULT 12)
   /*  Possible values for snaps_per_day: 24, 12, 6, 4  */
   IS
      CURSOR c_1
      IS
         SELECT job
           FROM user_jobs
          WHERE LOWER (TRIM (what)) LIKE '%statspack.snap%';

      var_snap_job        NUMBER;
      instno              NUMBER;
      jobno               NUMBER;
      var_snaps_per_day   NUMBER;
   BEGIN
      IF snaps_per_day > 12
      THEN
         var_snaps_per_day := 24;
      ELSIF snaps_per_day <= 12 AND snaps_per_day > 6
      THEN
         var_snaps_per_day := 12;
      ELSIF snaps_per_day <= 6 AND snaps_per_day > 4
      THEN
         var_snaps_per_day := 6;
      ELSE
         var_snaps_per_day := 4;
      END IF;

      OPEN c_1;

      LOOP
         FETCH c_1
          INTO var_snap_job;

         EXIT WHEN c_1%NOTFOUND;
         DBMS_JOB.remove (var_snap_job);
      END LOOP;

      CLOSE c_1;

      instno := instance_number;
      DBMS_JOB.submit (jobno,
                       'statspack.snap;',
                       TRUNC (SYSDATE + 1 / var_snaps_per_day, 'HH'),
                          'trunc(SYSDATE+1/'
                       || TO_CHAR (var_snaps_per_day)
                       || ',''HH'')',
                       TRUE,
                       instno
                      );
      COMMIT;
   END resubmit_snap_jobs;
END statspack_admin;
/
©2017 Edward Stoever