Had it for ages - I think I put it together 'round
8.1.5 when dbms_stats was looking good, but still
didn't work at all well at the SCHEMA or DATABASE
level....which of course, is probably still the case
:-)
The main thing of course was being able to control the
sample size based on segment size.  9.x now offers
that, but I don't particularly like the rather
expensive way it does it.
hth
connor
  -   Cherie_Machler_at_gelco.com wrote: > 
 > Connor,
 >
 > What version of Oracle was this coded for?
 >
 > Thanks,
 >
 > Cherie
 >
 >
 >
 >
 >
 >                     Connor
 >
 >
 >                     McDonald             To:
 > Multiple recipients of list ORACLE-L
 > <ORACLE-L_at_fatcity.com>
 >                     <hamcdc_at_yahoo.       cc:
 >
 >
 >                     co.uk>               Subject:
 >  RE: DBMS_STATS.GATHER_DATABASE_STATS analyzes SYS
 > and
 >                     Sent by:              SYSTEM
 > inde
 >
 >                     root_at_fatcity.c
 >
 >
 >                     om
 >
 >
 >
 >
 >
 >
 >
 >
 >                     10/07/02 11:18
 >
 >
 >                     AM
 >
 >
 >                     Please respond
 >
 >
 >                     to ORACLE-L
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 > Here is a work-in-progress utility, ie, I'm posting
 > this on an "all care, no responsibility" basis.
 > "Features" include:
 >
 > - will process all schemas or a nominated one
 > - has been deliberately restricted tables and
 > indexes
 > (so if you want lobs etc, you'll need to edit it a
 > little)
 > - can run in synchronous (foreground) mode or
 > asynchronous ( submits itself as a dbms_job)
 > - can run in parallel (multiple streams done via
 > modulo the object_id)
 > - has a debugging mode
 > - uses dbms_space to derive a meaningful estimate
 > size
 > for each segment
 > - records progress in v$session_longops
 > - doesn't go against DBA_SEGMENTS 'cos thats so slow
 > - cranks up sort_area_size to improve perf.
 >
 > Cheers
 > Connor
 >
 > create or replace
 > package     system.dbstat is
 >
 > procedure analyze_db (
 >              p_owner varchar2 default null,
 > --
 > if only one owner to be processed
 >              p_debug number default 0,
 > --
 > 0=do work, 1=msgs+work, 2=msgs only
 >              p_segment_type varchar2 default null,
 > --
 > TABLE or INDEX
 >              p_parallel number default 1,
 > --
 > concurrency (>1 means must be asych)
 >              p_mode varchar2 default 'S',
 > --
 > A=run as dbms_job, S=run synchronous
 >              p_int1 number default 1,
 > --
 > internal use only
 >              p_int2 number default 0) ;
 > --
 > internal use only
 > end;
 > /
 > create or replace
 > package body     system.dbstat is
 >
 > --
 >
 
 >
 > -- Routines
 > --
 >
 
 >
 >
 > procedure analyze_db (
 >              p_owner varchar2 default null,
 > --
 > if only one owner to be processed
 >              p_debug number default 0,
 > --
 > 0=do work, 1=msgs+work, 2=msgs only
 >              p_segment_type varchar2 default null,
 > --
 > TABLE or INDEX
 >              p_parallel number default 1,
 > --
 > concurrency (>1 means must be asych)
 >              p_mode varchar2 default 'S',
 > --
 > A=run as dbms_job, S=run synchronous
 >              p_int1 number default 1,
 > --
 > internal use only
 >              p_int2 number default 0) is
 > --
 > internal use only
 >
 >   type varchar_list is table of varchar2(80);
 >
 >   v_start             date   := sysdate;
 >   v_tot_count         number := 0;
 >   v_cum_count         number := 0;
 >   v_cum_bytes         number := 0;
 >
 >   v_owner             varchar_list;
 >   v_segment_name      varchar_list;
 >   v_segment_type      varchar_list;
 >   v_partitioned       varchar_list;
 >
 >   v_longop_rindex     pls_integer;
 >   v_longop_slno       pls_integer;
 >   v_job               pls_integer;
 >   v_job_plsql         varchar2(240);
 >
 >   procedure process_segment(p_owner
 > varchar2,p_segment_name varchar2,
 >                             p_segment_type
 > varchar2,p_part_name varchar2 default null,
 >                             p_granularity varchar2
 > default 'GLOBAL') is
 >     v_total_blocks      number;
 >     v_total_bytes       number;
 >     v_unused_blocks     number;
 >     v_unused_bytes      number;
 >     v_last_file_id      number;
 >     v_last_block_id     number;
 >     v_last_block        number;
 >     v_amount_to_analyze number;
 >     v_ana_command       varchar2(500);
 >   begin
 >
 >
 >
dbms_application_info.set_client_info(p_owner||','||p_segment_name||','
 > ||p_segment_type||','||p_part_name);
 >
 >     dbms_space.unused_space (
 >          p_owner,
 >          p_segment_name,
 >          p_segment_type,
 >          v_total_blocks,
 >          v_total_bytes,
 >          v_unused_blocks,
 >          v_unused_bytes,
 >          v_last_file_id,
 >          v_last_block_id,
 >          v_last_block,
 >          p_part_name);
 >
 > --
 > -- This gives a reasonable degree of analysis.  Up
 > to
 > about 10M is effectively a compute, and
 > -- it reduces from there, eventually down to about
 > 0.5% for a 1G segment
 > -- The formula is: percent to analyze := 500 *
 > power(used megabytes,-1.05)
 > -- with a ceiling of 99.99 percent (since dbms_stats
 > does not allow a '100' to be passed)
 > --
 >     v_amount_to_analyze :=
 >
least(99.99,round(131072000*power(greatest(v_total_bytes-v_unused_bytes,1),
 > -1.05),5));
 >
 >     if p_debug > 0 then
 >       dbms_output.put_line(p_segment_type||':
 > '||p_owner||'.'||p_segment_name||' '||p_part_name);
 >       dbms_output.put_line(v_total_bytes||' bytes
 > allocated');
 >
 >
dbms_output.put_line((v_total_bytes-v_unused_bytes)||'
 > bytes in use');
 >       dbms_output.put_line('Analyze
 > '||nvl(v_amount_to_analyze,100)||'%');
 >       dbms_output.put_line('---------------------');
 >     end if;
 >
 >     dbms_application_info.set_client_info('Obj:
 > '||v_cum_count||' '||p_owner||'.'||p_segment_name||'
 > '||
 >
 > (v_total_bytes-v_unused_bytes)||' byt
 > '||nvl(v_amount_to_analyze,100)||'%');
 >
 >     if p_debug < 2 then
 >
 >
dbms_application_info.set_session_longops(v_longop_rindex,
 > v_longop_slno,
 >             'Analyze', 0, 0, v_cum_count,
 > v_tot_count,
 > p_segment_type, 'objects');
 >         if p_segment_type like 'TABLE%' then   --
 > could be a table or a table partition
 >           sys.dbms_stats.gather_table_stats(
 >              ownname=>'"'||p_owner||'"',
 >              tabname=>'"'||p_segment_name||'"',
 >              granularity=>'ALL',
 >              estimate_percent=>v_amount_to_analyze,
 >              partname=>p_part_name);
 >         else
 >           sys.dbms_stats.gather_index_stats(
 >              ownname=>'"'||p_owner||'"',
 >              indname=>'"'||p_segment_name||'"',
 >              estimate_percent=>v_amount_to_analyze,
 >              partname=>p_part_name);
 >         end if;
 >         v_cum_count := v_cum_count + 1;
 >         v_cum_bytes := v_cum_bytes +
 > v_total_bytes-v_unused_bytes;
 >     end if;
 >   end;
 >
 > begin
 >   if upper(p_mode) not in ('A','S') then
 >      raise_application_error(-20000,'Mode must be A
 > or
 > S');
 >   end if;
 >   if p_parallel > 1 and upper(p_mode) != 'A' then
 >      raise_application_error(-20000,'Cannot run
 > parallel in synchronous mode');
 >   end if;
 >   if p_parallel not between 1 and 4 then
 >      raise_application_error(-20000,'Parallel
 > limited
 > to 1 to 4');
 >   end if;
 >
 >   if p_parallel > 1 or p_mode = 'A' then
 >     for i in 1 .. p_parallel loop
 >       v_job_plsql :=
 >
'dbstat.analyze_db('''||p_owner||''',0,'''||p_segment_type||
 >
 > ''',1,''S'','||p_parallel||','||(i-1)||');';
 >       if p_debug > 0 then
 >         dbms_output.put_line('Job: '||v_job_plsql);
 >       end if;
 >       if p_debug < 2 then
 >         dbms_job.submit(v_job,v_job_plsql);
 >       end if;
 >     end loop;
 >     commit;
 >     return;
 >   end if;
 >
 >   dbms_output.put_line('---------------------');
 >
 >   dbms_output.enable(999999);
 >
 >   if p_debug > 0 then
 >     execute immediate 'alter session set
 > sort_area_size = 8192000' ;
 >     execute immediate 'alter session set
 > sort_area_retained_size = 8192000' ;
 >     v_longop_rindex :=
 > dbms_application_info.set_session_longops_nohint;
 >   end if;
 >
 >   SELECT segment_TYPE,segment_NAME,owner,
 > decode(subname,null,'NO','YES') partitioned
 >   bulk collect into
 >          v_segment_type, v_segment_name, v_owner,
 > v_partitioned
 >   from ( select u.name owner, o.name segment_name,
 > o.subname, so.object_type segment_type, o.obj#
 > object_id
 >          from sys.user$ u, sys.obj$ o, sys.ts$ ts,
 > sys.seg$ s, sys.file$ f,
 >               ( select 'TABLE' object_type, 2
 > object_type_id, 5 segment_type_id, t.obj#, t.file#,
 > t.block# , t.ts#
 >                 from sys.tab$ t
 >                 where bitand(t.property, 1024) = 0
 >                 and   bitand(t.property,8192) = 0
 >                 union all
 >                 select 'INDEX', 1, 6, i.obj#,
 > i.file#,
 > i.block#, i.ts#
 >                 from sys.ind$ i
 >                 where i.type# in (1, 2, 3, 4, 6, 7,
 > 9)
 > ) so
 >          where s.file# = so.file#
 >            and s.block# = so.block#
 >            and s.ts# = so.ts#
 >            and s.ts# = ts.ts#
 >            and o.obj# = so.obj#
 >            and o.owner# = u.user#
 >            and s.type# = so.segment_type_id
 >            and o.type# = so.object_type_id
 >            and s.ts# = f.ts#
 >            and s.file# = f.relfile#
 >            and u.name not in ('SYS','SYSTEM'))
 >   where  owner = nvl(upper(p_owner),owner)
 >   and    segment_type =
 > nvl(upper(p_segment_type),segment_type)
 >   and    mod(object_id,p_int1) = p_int2;
 >
 >   v_tot_count := v_segment_type.count;
 >   for i in v_segment_type.first ..
 > v_segment_type.last
 > loop
 >       if v_partitioned(i) = 'YES' then
 >         for j in (
 >           SELECT O.SUBNAME PART_NAME,
 >                  decode(O.TYPE#,19,'TABLE
 > PARTITION',
 >                                 20,'INDEX
 > PARTITION',
 >                                 34,'TABLE
 > SUBPARTITION',
 >                                 35,'INDEX
 > SUBPARTITION') segment_type
 >           FROM SYS.USER$ U,SYS.OBJ$ O
 >           WHERE U.NAME = v_owner(i)
 >           AND O.OWNER# = U.USER#
 >           AND O.NAME = v_segment_name(i)
 >           AND O.TYPE# in (19 ,20,34,35)
 >           ORDER BY PART_NAME ) loop
 >
 >
process_segment(v_owner(i),v_segment_name(i),j.segment_type,j.part_name,'PARTITION');
 >
 >         end loop;
 >       else
 >
 >
process_segment(v_owner(i),v_segment_name(i),v_segment_type(i));
 >       end if;
 >   end loop;
 >   dbms_output.put_line('Objects Analyzed:
 > '||v_cum_count);
 >   dbms_output.put_line('Bytes scanned:
 > '||v_cum_bytes);
 >   dbms_output.put_line('Elapsed Time:
 > '||round((sysdate-v_start)*86400,1));
 > end;
 >
 > END;
 > /
 >
 >
 >  --- "Jesse, Rich" <Rich.Jesse_at_qtiworld.com> wrote:
 > >
 > Yes, the DBMS_STATS package is very quirky in 8i,
 > > IMHO.  Knowing the bug in
 > > DATABASE_STATS, I've written a procedure to
 > > iteratively use SCHEMA_STATS
 > > instead.  Of course, this too has a bug that will
 > > report ORA-1403 on the
 > > "first" table in the schema, so I needed to code
 > > around that.
 > >
 > > And for all this trouble Oracle still recommends
 > > using DBMS_STATS over
 > > ANALYZE.  Then fix it!  <sigh>
 > >
 > > Rich Jesse
 > System/Database
 > > Administrator
 > > Rich.Jesse_at_qtiworld.com              Quad/Tech
 > > International, Sussex, WI USA
 > >
 > >
 > > > -----Original Message-----
 > > > From: Post, Ethan [mailto:Ethan.Post_at_ps.net]
 > > > Sent: Friday, October 04, 2002 5:09 PM
 > > > To: Multiple recipients of list ORACLE-L
 > > > Subject: RE: DBMS_STATS.GATHER_DATABASE_STATS
 > > analyzes SYS and SYSTEM
 > > > inde
 > > >
 > > >
 > > > Arrgggg...
 > > >
 > > > So anyway, I am thinking, hey it's high time I
 > > start using DBMS_STATS
 > > > instead of my own procedure so I kick of the
 > > following
 > > > (Oracle 8.1.7.4).
 > > > After the first run I have SYS and SYSTEM stats
 > on
 > > indexes
 > > > and on other
 > > > schemas with NO STATS it just ignored those
 > tables
 > > even
 > > > though you can see I
 > > > have GATHER EMPTY below.  So I kick it off again
 > > and guess
 > > > what, it starts
 > > > analyzing the tables it missed the first time,
 > > including SYS
 > > > and SYSTEM.
 > > > Guess I am going to use
 > > DBMS_STATS.GATHER_TABLE_STATS and be
 > > > a bit more
 > > > specific about what I get.
 > > --
 > > Please see the official ORACLE-L FAQ:
 > > http://www.orafaq.com
 > > --
 > > Author: Jesse, Rich
 > >   INET: Rich.Jesse_at_qtiworld.com
 > >
 > > Fat City Network Services    -- 858-538-5051
 > > http://www.fatcity.com
 > > San Diego, California        -- Mailing list and
 > web
 > > hosting services
 > >
 >
 
 > > To REMOVE yourself from this mailing list, send an
 > > E-Mail message
 > > to: ListGuru_at_fatcity.com (note EXACT spelling of
 > > 'ListGuru') and in
 > > the message BODY, include a line containing: UNSUB
 > > ORACLE-L
 > > (or the name of mailing list you want to be
 > removed
 > > from).  You may
 > > also send the HELP command for other information
 > > (like subscribing).
 >
 > =====
 > Connor McDonald
 > http://www.oracledba.co.uk
 > http://www.oaktable.net
 >
 > "Remember amateurs built the ark - Professionals
 > built the Titanic"
 >
 > __________________________________________________
 > Do You Yahoo!?
 > Everything you'll ever need on one web page
 > from News and Sport to Email and Music Charts
 > http://uk.my.yahoo.com
 > --
 > Please see the official ORACLE-L FAQ:
 > http://www.orafaq.com
 > --
 > Author: =?iso-8859-1?q?Connor=20McDonald?=
 >   INET: hamcdc_at_yahoo.co.uk
 >
 > Fat City Network Services    -- 858-538-5051
 > http://www.fatcity.com
 > San Diego, California        -- Mailing list and web
 > hosting services
 >
 
 > To REMOVE yourself from this mailing list, send an
 > E-Mail message
 > to: ListGuru_at_fatcity.com (note EXACT spelling of
 > 'ListGuru') and in
 > the message BODY, include a line containing: UNSUB
 > ORACLE-L
 > (or the name of mailing list you want to be removed
 > from).  You may
 > also send the HELP command for other information
 > (like subscribing).
 >
 >
 >
 >
 > --
 > Please see the official ORACLE-L FAQ:
 > http://www.orafaq.com
 > --
 > Author:
 >   INET: Cherie_Machler_at_gelco.com
 >
 > Fat City Network Services    -- 858-538-5051
 > http://www.fatcity.com
 > San Diego, California        -- Mailing list and web
 > hosting services
 >
 
 > To REMOVE yourself from this mailing list, send an
 > E-Mail message
 > to: ListGuru_at_fatcity.com (note EXACT spelling of
 > 'ListGuru') and in
 > the message BODY, include a line containing: UNSUB
 > ORACLE-L
 > (or the name of mailing list you want to be removed
 > from).  You may
 > also send the HELP command for other information
 > (like subscribing).
 
 
Connor McDonald
http://www.oracledba.co.uk
http://www.oaktable.net
"Remember amateurs built the ark - Professionals built the Titanic"
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com
-- 
Please see the official ORACLE-L FAQ: http://www.orafaq.com
-- 
Author: =?iso-8859-1?q?Connor=20McDonald?=
  INET: hamcdc_at_yahoo.co.uk
Fat City Network Services    -- 858-538-5051 http://www.fatcity.com
San Diego, California        -- Mailing list and web hosting services
---------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: ListGuru_at_fatcity.com (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB ORACLE-L
(or the name of mailing list you want to be removed from).  You may
also send the HELP command for other information (like subscribing).
Received on Tue Oct 08 2002 - 04:11:08 CDT