Wikipedia

Search results

Statistics - User Object, System, Fixed Object, and Dictionary Statistics Topics

Good Luck !

User Object Statistics

http://www.dba-oracle.com/t_gather_stats_job.htm
Improvement of AUTO sampling statistics gathering on 11g - The Oracle Optimizer Development Group

Statistics on Partitioned Tables

Managing Statistics on Large Partitioned Tables - The Oracle Optimizer Development Group
Oracle 11g Incremental Global Statistics on Partitioned Tables - Greg Rahn
Data Warehousing and Statistics in Oracle 11g - Robin Moffatt
11g Incremental Partition Statistics Review - Randolf Geist
Managing Optimizer Statistics in Oracle Database 11g - Maria Colgan
-- Turn on incremental stats for all partitioned tables > 500mb
  SELECT OWNER, SEGMENT_NAME, SUM (BYTES) / 1024 / 1024 / 1024 AS GB, 
  DBMS_STATS.GET_PREFS('INCREMENTAL', OWNER, segment_name) AS INCREMENTAL
    FROM DBA_SEGMENTS
   WHERE SEGMENT_TYPE = 'TABLE PARTITION' AND SEGMENT_NAME NOT LIKE '%$%'
GROUP BY OWNER, SEGMENT_NAME
  HAVING SUM (BYTES) / 1024 / 1024 / 1024 >= 0.5
ORDER BY 3 DESC;

BEGIN
  FOR cur IN (
    SELECT OWNER, SEGMENT_NAME, SUM (BYTES) / 1024 / 1024 / 1024 AS GB
      FROM DBA_SEGMENTS
     WHERE SEGMENT_TYPE = 'TABLE PARTITION' 
       AND SEGMENT_NAME NOT LIKE '%$%'
  GROUP BY OWNER, SEGMENT_NAME
    HAVING SUM (BYTES) / 1024 / 1024 / 1024 >= 0.5)
  LOOP
    DBMS_OUTPUT.PUT_LINE('Processing '||cur.SEGMENT_NAME);
    DBMS_STATS.set_table_prefs(cur.owner, cur.segment_name, 'INCREMENTAL', 'TRUE');

  END LOOP;
END;
/

System Statistics

Recording Oracle System Stats for Historical Analysis

Fixed Object Statistics

Oracle Optimizer Blog - Fixed Object Statistics and Why They Are Important

Dictionary Statistics

exec dbms_stats.gather_dictionary_stats;

More Statistics Topics...

Statistics Freshness Check

Find Candidates for Statistics Gathering

Anything that has more than 10% changes (inserts+deletes+updates) since last analyze should probably be analyzed again. This can be checked Oracle's Table Monitoring feature. This query will show a list of database tables with the most changed first.

Verify Table Monitoring is On

Survey table monitoring

SELECT MONITORING, 
       COUNT(*)
  FROM USER_TABLES 
GROUP BY MONITORING;

Turn table monitoring on for 1 table

ALTER TABLE [TABLE_NAME] MONITORING;

Turn table monitoring on for all tables that need it

DECLARE
  my_sql VARCHAR2(256);
BEGIN
FOR c1 IN (SELECT TABLE_NAME 
           FROM USER_TABLES 
           WHERE MONITORING='NO')
LOOP
  my_sql := 'ALTER TABLE ' || c1.TABLE_NAME || ' MONITORING');
  execute immediate my_sql;
  
END LOOP;
END;
/

Updating Monitoring Information

exec DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO();

View data about monitored tables

This query will give information about table monitoring since the table's last analyze.
-- Statistics Freshness
-- David Mann    http://ba6.us
-- Display Change % and details for monitored tables. These tables are
-- candidates for statistics gathering once they hit the STALE_PERCENT 
-- threshold defined in sys.optstat_hist_control$
SELECT ATM.TABLE_OWNER,  
       ATM.TABLE_NAME,  
       ATM.PARTITION_NAME as Part,
       ATM.SUBPARTITION_NAME as SubPart, 
       AT.NUM_ROWS as Analyzed_NumRows,  
       ATM.INSERTS,  
       ATM.UPDATES,  
       ATM.DELETES,  
      (ATM.INSERTS+ATM.UPDATES+ATM.DELETES) as Changes,  
      ROUND(((ATM.INSERTS+ATM.UPDATES+ATM.DELETES)/NUM_ROWS)*100,2) as STALE_PCT,  
      (SELECT LAST_ANALYZED FROM ALL_TABLES WHERE OWNER=ATM.TABLE_OWNER and TABLE_NAME=ATM.TABLE_NAME) as LAST_ANALYZED  
 FROM ALL_TAB_MODIFICATIONS ATM,   
      ALL_TABLES AT
WHERE ATM.TABLE_OWNER=AT.OWNER  
  AND ATM.TABLE_NAME=AT.TABLE_NAME  
  AND ATM.TABLE_NAME NOT LIKE 'BIN$%' 
  AND ATM.TABLE_OWNER NOT IN ('SYS','SYSTEM')  
  AND NUM_ROWS  0  
ORDER BY 10 DESC;
Note that there are some quirks with updates to _TAB_MODIFICATIONS: o Stats flush to _TAB_MODIFICATIONS are noted as every 3 hours in 762738.1 o If users modify an object in another schema, those DML counts do not show up in USER_TAB_MODIFICATIONS

References

Oracle 10.2 Documentation - Determining Stale Statistics

Browsing Current Table and Column Statistics

Column Monitoring

How have columns been used in SQL statements? The types of joins done on a column and how it is involved in the WHERE clause of queries may affect CBO behavior.
SELECT * FROM (
    SELECT (SELECT username FROM dba_users WHERE user_id = o.owner#) AS owner, 
           o.NAME AS table_name, 
           c.NAME AS column_name, 
           o.obj# AS table_object_id,
           cu.intcol# AS intcol#, 
           cu.equality_preds AS equality, 
           cu.equijoin_preds AS equijoin,
           cu.nonequijoin_preds AS noneequijoin, 
           cu.range_preds AS RANGE, 
           cu.like_preds AS "LIKE", 
           cu.null_preds AS "NULL",
           cu.TIMESTAMP
        FROM SYS.col$ c, SYS.col_usage$ cu, SYS.obj$ o, SYS.user$ u
        WHERE c.obj# = cu.obj#(+) AND c.intcol# = cu.intcol#(+) AND c.obj# = o.obj# AND o.owner# = u.user#) 
      WHERE OWNER='&OWNERNAME.' AND TABLE_NAME='&TABLENAME.';

Table Statistics

SELECT * 
  FROM DBA_TAB_STATISTICS 
 WHERE owner='&OWNERNAME.'
 ORDER BY TABLE_NAME;

Partition Statistics

SELECT * 
  FROM DBA_TAB_STATISTICS 
 WHERE OWNER='&OWNER.' 
   AND PARTITION_NAME IS NOT NULL 
   AND TABLE_NAME NOT LIKE 'BIN$%'
 ORDER BY table_name, partition_position;

Column Statistics

SELECT *
  FROM DBA_TAB_COL_STATISTICS tcs 
 WHERE tcs.owner = '&OWNERNAME.' AND tcs.table_name = '&TABLENAME.'
 ORDER BY 1,2,3;
SELECT TABLE_NAME,  
       COLUMN_NAME, 
       NUM_DISTINCT, 
       (SELECT NUM_ROWS FROM USER_TABLES WHERE TABLE_NAME=tcs.TABLE_NAME) as NUM_ROWS, 
       SAMPLE_SIZE,
       HISTOGRAM,
       NUM_BUCKETS
  FROM USER_TAB_COL_STATISTICS tcs 
 WHERE lower(tcs.table_name) IN ('')
 ORDER BY 1,2,3;

Are histograms in use?

SELECT TABLE_NAME, 
       COLUMN_NAME, 
       COUNT(*) 
  FROM USER_TAB_HISTOGRAMS 
 GROUP BY TABLE_NAME, 
          COLUMN_NAME 
HAVING COUNT(*) > 2 ;

Browsing Historical Table and Column Statistics

Historical statistics for the past 31 days are stored in SYS tables/SYSAUX tablespaceon 10g and 11g Oracle databases. So whenever the nightly Statistics Gathering job regenerates statistics for an object, the the old value is stored in these history tables. Old historical stats past the time limit are purged as needed. The retention period can be modified using the ALTER_STATS_HISTORY_RETENTION procedure. Some ERP systems have a lot of turnover in statistics and might benefit from a shorter retention period.

Statistics Gathering Job History

Check the history of the GATHER_STATS_JOB
SELECT * FROM DBA_SCHEDULER_JOBS WHERE JOB_NAME = 'GATHER_STATS_JOB';

Table Stats History

 -- All stats history for user objects
 -- Sort: most recent at top
 SELECT do.owner, 
        do.object_name, 
        oth.* 
   FROM SYS.WRI$_OPTSTAT_TAB_HISTORY oth join dba_objects do on oth.obj#=do.object_id
  WHERE OWNER NOT IN ('SYS','SYSTEM')
  ORDER BY savtime desc;
-- Get historical Statistics info for 1+ Tables
WITH TableList as (select object_id, object_name 
               from dba_objects 
              where object_type='TABLE' 
                and object_name IN ('TABLE_1','TABLE_2',...)) 
select OBJECT_NAME as TABLE_NAME, 
       TO_CHAR(ANALYZETIME,'MM/DD/YYYY HH24:MI') as AnalyzeTime_Formatted,
       OTH.*
  From SYS.WRI$_OPTSTAT_TAB_HISTORY OTH, TableList 
 where OTH.OBJ# = TableList.OBJECT_ID
 ORDER BY table_name, analyzetime;

Histogram Stats History Summary

-- Get histogram summary info for 1 column
WITH TabColInfo AS (select OBJ#, COL# from sys.COL$ where OBJ# in (select object_id 
               from dba_objects 
              where object_type='TABLE' 
                and object_name='&my_table_name.')
              and NAME='&my_column_name.')
select SAVTIME, COUNT(BUCKET) From SYS.WRI$_OPTSTAT_HISTGRM_HISTORY HH, TabColInfo TCI
WHERE HH.OBJ#=TCI.OBJ# and HH.INTCOL#=TCI.COL# GROUP BY SAVTIME;

Default Stats Jobs

Show current Global defaults for object stats gathering

These can be set with the DBMS_STATS.SET_GLOBAL_PREFS procedure.
SELECT sname as Name,
       SVAL1 || SPARE4 AS Value
  FROM sys.optstat_hist_control$
 ORDER BY 1;

View info About Nightly Stats Collection Jobs (10g)

SELECT JOB_NAME, 
       SCHEDULE_NAME, 
       JOB_CLASS, 
       RUN_COUNT, 
       LAST_START_DATE, 
       LAST_RUN_DURATION, 
       NEXT_RUN_DATE 
  FROM DBA_SCHEDULER_JOBS 
 WHERE JOB_NAME = 'GATHER_STATS_JOB';

View info About Nightly Stats Collection Jobs (11g)

select window_name, job_start_time, job_duration
   from dba_autotask_job_history
  where client_name = 'auto optimizer stats collection'
  order by job_start_time desc;

Exporting/Importing Schema Statistics

1. Create the statistics table.

exec DBMS_STATS.CREATE_STAT_TABLE(ownname =>'SCHEMA_NAME' ,stattab => 'STATS_TABLE' , tblspace => 'STATS_TABLESPACE');
Example:
exec DBMS_STATS.CREATE_STAT_TABLE(ownname =>'SYSTEM',stattab => 'STATS_TABLE');

2. Export statistics to statistics table

EXEC DBMS_STATS.EXPORT_SCHEMA_STATS('ORIGINAL_SCHEMA' ,'STATS_TABLE',NULL,'SYSTEM');

3. Import statistics into the data dictionary.

exec DBMS_STATS.IMPORT_SCHEMA_STATS('NEW_SCHEMA','STATS_TABLE',NULL,'SYSTEM');

4. Drop the statistics table.

exec DBMS_STATS.DROP_STAT_TABLE('SYSTEM','STATS_TABLE');

Gathering Stats with SIZE AUTO

Pros

Works for most cases. Job is automatically created and scheduled when database is created.

Cons

  • Not always clear when histograms will be used.
  • Column usage can affect stats gathering, ie difference between Production load and Test load on the same datasets
  • See Hermant's article on Column Usage affecting histograms herehere, and here.

Rolling Back Statistics

If your statistics get corrupted or mismanaged for any reason you may be able to roll back to a previous version of your stats. Here is how you can do it for 1 schema:

1) Backup the current stats for your schema

BEGIN
  dbms_stats.export_schema_stats( ownname=>'[SCHEMA_NAME]'
                                , stattab=>'STAT_BACKUP_[SCHEMA_NAME]_[DATE]'
                                , statown => 'SYS'
                                , statid=>'CURRENT_STATS');
END;
/
Note: You can watch progress of this operation by watching long operations view (SQL is below).

2) Delete the schema's stats

This is for safety. If you happened to have new stats generated recently these will still be in play unless you delete them to start with a clean slate.
BEGIN
  DBMS_STATS.DELETE_SCHEMA_STATS (
    ownname          => '[SCHEMA_NAME]'
  );
  COMMIT;
END;
/
Note: You can watch progress of this operation by watching long operations view (SQL is below).

3) Load stats from a previous point in time

Substitute appropriate date in the following to_timestamp() function call.
BEGIN
  DBMS_STATS.RESTORE_SCHEMA_STATS( 
   ownname => '[SCHEMA_NAME]', 
   as_of_timestamp  =>to_timestamp('04-SEP-2014 07.00.00.000000 PM','dd-mon-yyyy hh.mi.ss.ff am') );
commit;
END;
/
Note: You can watch progress of this operation by watching long operations view (SQL is below).

4) Flush shared pool

Run the following on all instances:
ALTER SYSTEM FLUSH SHARED POOL;
Your reverted stats should now be in play for all newly issued queries.

Reference : Long operations view

SELECT ROUND(sofar/totalwork*100,2), v$session_longops.*
  FROM v$session_longops
 WHERE sofar  totalwork
 ORDER BY target, sid;

Statistics on Partitioned Tables

Table NUM_ROWS vs Sum of Partition NUM_ROWS

WITH 
     -- List all user tables that have partitions
     TabList AS (
     SELECT DISTINCT TABLE_OWNER, TABLE_NAME 
       FROM dba_tab_partitions 
      WHERE TABLE_OWNER NOT IN ('SYSTEM','SYS') ORDER BY 1,2),
     -- Summarize partition details
     PartTotals AS (
     SELECT TABLE_OWNER, TABLE_NAME, SUM(NUM_ROWS) as PARTS_TOTAL_ROWS, MAX(LAST_ANALYZED) as MAX_PART_LAST_ANALYZED, MIN(LAST_ANALYZED) as MIN_PART_LAST_ANALYZED 
       FROM DBA_TAB_PARTITIONS 
      GROUP BY TABLE_OWNER, TABLE_NAME),
     -- Summarize Table vs Partition NUM_ROWS and ANALYZE_DATE info
     Summary AS (
     SELECT TABLIST.TABLE_OWNER, 
            TABLIST.TABLE_NAME, 
            DBA_TABLES.LAST_ANALYZED as TAB_LAST_ANALYZED,
            PartTotals.MIN_PART_LAST_ANALYZED,
            PartTotals.MAX_PART_LAST_ANALYZED,
            DBA_TABLES.NUM_ROWS as TABLE_ROWS,
            PartTotals.PARTS_TOTAL_ROWS,
            ABS(NVL(DBA_TABLES.NUM_ROWS,0)-NVL(PartTotals.PARTS_TOTAL_ROWS,0)) as RowDifference,
            GREATEST(DBA_TABLES.NUM_ROWS,PartTotals.PARTS_TOTAL_ROWS) as MaxNumRows
       FROM TabList, DBA_TABLES, PartTotals
      WHERE TabList.TABLE_OWNER=DBA_TABLES.OWNER and TabList.TABLE_NAME=DBA_TABLES.TABLE_NAME
        AND TabList.TABLE_OWNER=PartTotals.TABLE_OWNER AND TabList.TABLE_NAME=PartTotals.TABLE_NAME)
-- Calculate Percent Difference so we can see how much the Table vs Partition Num Rows differ
SELECT SUMMARY.*
       ,ROUND(Summary.RowDifference/NVL(MaxNumRows+1,1)*100,2) AS PctDiff 
  FROM SUMMARY 
 ORDER BY ROUND(Summary.RowDifference/NVL(MaxNumRows+1,1)*100,2);

Other Articles

http://blogs.oracle.com/optimizer/entry/maintaining_statistics_on_large_partitioned_tables

No comments:

Post a Comment