1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web...

105
1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version

Transcript of 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web...

Page 1: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

1 © 2010 Julian Dyke juliandyke.com

Optimizer Statistics

Julian Dyke

Independent Consultant

Web Version

Page 2: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

2 © 2010 Julian Dyke juliandyke.com

Agenda

Statistics Strategies ANALYZE DBMS_STATS ANALYZE versus DBMS_STATS System Statistics Automatic Statistics Collection Statistics History Manual Statistics Partition Statistics Oracle 11g Enhancements

Page 3: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

3 © 2010 Julian Dyke juliandyke.com

StatisticsStrategies

Page 4: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

4 © 2010 Julian Dyke juliandyke.com

Statistics Strategies Introduction Only gather statistics when object has changed significantly

Consider generating manual statistics for: Very large objects Temporary tables Highly volatile tables

Try to collect statistics during a specified window Do not execute SQL statements during statistics collection Use DBMS_STATS parallelism Review sample sizes for very large objects

In complex databases do not rely on Auto job Unpredictable collection behaviour / duration Unpredictable execution plan changes

See Metalink Note 44961.1 - Statistics Gathering; Frequency and Strategy

Page 5: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

5 © 2010 Julian Dyke juliandyke.com

ANALYZE

Page 6: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

6 © 2010 Julian Dyke juliandyke.com

ANALYZEIntroduction SQL statement

Introduced in Oracle 7.0 Collects object statistics for Cost Based Optimizer

Initially collected statistics on tables and indexes Subsequently on histograms

Advantages Online analyze - Oracle 9.0 and above Optionally validates structure of tables, indexes and clusters Optionally detects chained / migrated rows

Disadvantages Serial statistics collection only Limited partition-awareness

Page 7: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

7 © 2010 Julian Dyke juliandyke.com

ANALYZEVALIDATE STRUCTURE Syntax is

ANALYZE INDEX <index_name> VALIDATE STRUCTURE;

Populates session-level dynamic performance views INDEX_STATS INDEX_HISTOGRAMS

Reports index statistics including: height number of leaf blocks number of branch blocks number of distinct keys

Reports space released by deletions Use to determine when to coalesce or rebuild index

Recommends index compression columns Use to determine which indexes should be compressed

Page 8: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

8 © 2010 Julian Dyke juliandyke.com

ANALYZEVALIDATE STRUCTURE ONLINE Introduced in Oracle 9.0.1 Syntax is

ANALYZE INDEX <index_name> VALIDATE STRUCTURE ONLINE;

ONLINE option only checks structure does not require TM (DML) lock does not populate INDEX_STATS or INDEX_HISTOGRAM

Page 9: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

9 © 2010 Julian Dyke juliandyke.com

DBMS_STATS

Page 10: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

10

© 2010 Julian Dyke juliandyke.com

DBMS_STATSIntroduction PL/SQL supported package

Introduced in Oracle 8.1.5 In Oracle 11.1 there are 107 subroutines

Defined in $ORACLE_HOME/rdbms/admin/dbmsstat.sql

Advantages Parallel statistics collection Partition-awareness

Disadvantages Cannot perform structure validation Cannot detect chaining / migration

Page 11: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

11 © 2010 Julian Dyke juliandyke.com

DBMS_STATSGathering Statistics Statistics can be gathered using the following subroutines:

GATHER_DATABASE_STATS GATHER_SCHEMA_STATS GATHER_TABLE_STATS GATHER_INDEX_STATS

These routines allow you to specify: Sample size Granularity (partitioned tables only) Histogram policy Cursor invalidation policy

Page 12: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

12

© 2010 Julian Dyke juliandyke.com

DBMS_STATSDeleting Statistics Statistics can be deleted using the following subroutines:

DELETE_DATABASE_STATS DELETE_SCHEMA_STATS DELETE_TABLE_STATS DELETE_INDEX_STATS DELETE_COLUMN_STATS

DELETE_TABLE_STATS includes CASCADE_PART - optionally delete partition statistics CASCADE_COLUMNS - optionally delete column statistics CASCADE_INDEXES - optionally delete index statistics

DELETE_INDEX_STATS, DELETE_COLUMN_STATS include: CASCADE_PART - optionally delete partition statistics

Page 13: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

13

© 2010 Julian Dyke juliandyke.com

DBMS_STATSStatistics Tables Used to

export / import statistics store object statistics values PRIOR to GATHER operations

To create a statistics table use CREATE_STATS_TABLE. For example:

dbms_stats.create_stats_table (

ownname => 'SYSTEM',tabname => 'STATS1',tblspace=> 'SYSAUX'

);

To drop a statistics table use DROP_STATS_TABLE

Page 14: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

14

© 2010 Julian Dyke juliandyke.com

DBMS_STATSExporting and Importing Statistics Statistics can be exported to a statistics table using:

EXPORT_COLUMN_STATS EXPORT_DATABASE_STATS EXPORT_INDEX_STATS EXPORT_SCHEMA_STATS EXPORT_TABLE_STATS

Statistics can be imported from a statistics table using: IMPORT_COLUMN_STATS IMPORT_DATABASE_STATS IMPORT_INDEX_STATS IMPORT_SCHEMA_STATS IMPORT_TABLE_STATS

To transfer the statistics to another database export and import the statistics table

Page 15: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

15

© 2010 Julian Dyke juliandyke.com

DBMS_STATSOPTIONS parameter Specifies how to determine which objects to gather statistics for:

GATHER - gather statistics for all objects GATHER AUTO - gather statistics for all objects needing new statistics GATHER STALE - gather statistics for all objects having stale statistics GATHER EMPTY- gather statistics for all objects having no statistics LIST AUTO - list objects needing new statistics LIST STALE - list objects having stale statistics LIST EMPTY - list objects having stale statistics

The OBJLIST parameter must be specified as an OUT parameter for the LIST options

GATHER STALE and GATHER EMPTY can also return a list of objects if this parameter is specified

Page 16: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

16

© 2010 Julian Dyke juliandyke.com

DBMS_STATSOPTIONS parameter If GATHER STALE is specified statistics will be gathered for objects where at

least 10% of rows have changed Total of INSERTS, UPDATES and DELETES since last statistics collection

In Oracle 10g percentage is fixed at 10% In Oracle 11g percentage is user-configurable

Page 17: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

17

© 2010 Julian Dyke juliandyke.com

DBMS_STATSStale Statistics In Oracle 10.1 and above table modification statistics:

are enabled if STATISTICS_LEVEL is TYPICAL or ALL are disabled if STATISTICS_LEVEL is BASIC

are collected in the SGA

are automatically flushed to SYS.MON_MODS$ by SMON background process every 15 minutes to SYS.MON_MODS$ if a significant number of rows has changed (possibly 10%)

can be manually flushed to SYS.MON_MOD$ using: DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO

are reported in DBA_TAB_MODIFICATIONS

Page 18: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

18

© 2010 Julian Dyke juliandyke.com

DBMS_STATSStale Statistics SYS.MON_MODS$ has the following columns:

Column Name Data Type

OBJ# NUMBER

INSERTS NUMBER

UPDATES NUMBER

DELETES NUMBER

TIMESTAMP DATE

FLAGS NUMBER

DROP_SEGMENTS NUMBER

Page 19: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

19

© 2010 Julian Dyke juliandyke.com

DBMS_STATSStale Statistics In Oracle 8i, table modification monitoring can only be enabled manually

using:

ALTER TABLE <table_name> MONITORING;ALTER TABLE <table_name> NOMONITORING;

In Oracle 9i, table modification monitoring can also be enabled using

DBMS_STATS.ALTER_SCHEMA_TAB_MONITORING ('<owner>',TRUE);DBMS_STATS.ALTER_DATABASE_TAB_MONITORING (TRUE);

Reported in DBA_TABLES.MONITORING

In Oracle 10.1 and above MONITORING clause is deprecated and ignored

Page 20: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

20

© 2010 Julian Dyke juliandyke.com

DBMS_STATSESTIMATE_PERCENT Parameter Specified using ESTIMATE_PERCENT parameter in

GATHER_DATABASE_STATS GATHER_DICTIONARY_STATS GATHER_INDEX_STATS GATHER_SCHEMA_STATS GATHER_TABLE_STATS

Valid range is 0.000001 to 100

NULL means COMPUTE

Default (10.2) is DBMS_STATS.AUTO_SAMPLE_SIZE Oracle determines sample size automatically

Default can be changed using SET_PARAM procedure

Page 21: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

21

© 2010 Julian Dyke juliandyke.com

DBMS_STATSGRANULARITY Parameter Only relevant for partitioned objects

ALL - gather global, partition and subpartition statistics AUTO - determine granularity based on partitioning type. DEFAULT - gather global and partition-level statistics. Now obsolete. Use

GLOBAL AND PARTITION instead GLOBAL - gather global statistics GLOBAL AND PARTITION - gather global and partition-level statistics PARTITION - gather partition-level statistics SUBPARTITION - gather subpartition-level statistics

In Oracle 10.2 default is AUTO (not DEFAULT)

Page 22: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

22

© 2010 Julian Dyke juliandyke.com

DBMS_STATSNO_INVALIDATE parameter In earlier versions ANALYZE and DBMS_STATS gather procedures always

invalidated cursors referencing affected object

In Oracle 10.1 and above, invalidation can be controlled using NO_INVALIDATE parameter

TRUE - do not invalidate dependent cursors FALSE - invalidate dependent cursors DBMS_STATS.AUTO_INVALIDATE (default) - Oracle determines whether

to invalidate dependent cursors or not.

In Oracle 10.2 the default value can be changed using SET_PARAM procedure

Only relevant for DBMS_STATS gather procedures ANALYZE always invalidates analyzed objects

Page 23: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

23

© 2010 Julian Dyke juliandyke.com

DBMS_STATSData Dictionary Statistics Oracle recommends that data dictionary statistics are collected in Oracle

9.0.1 and above

Subroutines are: GATHER_DICTIONARY_STATS DELETE_DICTIONARY_STATS EXPORT_DICTONARY_STATS RESTORE_DICTIONARY_STATS

In Oracle 9i data dictionary statistics should only be collected using:

dbms_stats.gather_schema_stats (ownname => 'SYS',cascade=> TRUE);

In Oracle 9i data dictionary statistics can be deleted using:

dbms_stats.delete_schema_stats (ownname => 'SYS');

See Metalink Note 245051.1

Note ANALYZE should not be used with tables owned by SYS. See Metalink Note 35272.1

Page 24: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

24

© 2010 Julian Dyke juliandyke.com

DBMS_STATSFixed Object Statistics In Oracle 10.1 and above Oracle recommends that statistics are collected on

fixed objects These include X$ and V$ views

Subroutines include: GATHER_FIXED_OBJECTS_STATS DELETE_FIXED_OBJECTS_STATS EXPORT_FIXED_OBJECT_STATS RESTORE_FIXED_OBJECTS_STATS

For example:

dbms_stats.gather_fixed_objects_stats;

Only gather fixed object statistics after the database has been running a representative workload

See Metalink Note 272479.1

Page 25: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

25

© 2010 Julian Dyke juliandyke.com

DBMS_STATSMETHOD_OPT Parameter Specifies histogram collection policy

Can be specified for: GATHER_DATABASE_STATS, GATHER_DICTIONARY_STATS, GATHER_SCHEMA_STATS GATHER_TABLE_STATS

Default is FOR ALL COLUMNS SIZE AUTO Uses data from COL_USAGE$ table

Page 26: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

26

© 2010 Julian Dyke juliandyke.com

DBMS_STATSMETHOD_OPT Parameter Syntax is:

FOR ALL [ INDEXED | HIDDEN ] COLUMNS [ size_clause ]

FOR COLUMNS [ [ size_clause ] column|attribute [size_clause][, column|attribute [size_clause]..]

size_clause is:

SIZE { integer | REPEAT | AUTO | SKEWONLY }

where: integer - number of histogram buckets (1..254) REPEAT - only collect histograms for columns that already have

histograms AUTO - determine which columns need histograms automatically SKEWONLY - determine which columns need histograms based on data

distribution

Page 27: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

27

© 2010 Julian Dyke juliandyke.com

DBMS_STATSColumn Usage Monitoring Column usage is recorded in SYS.COL_USAGE$

Column Name Data Type

OBJ# NUMBER

INTCOL# NUMBER

EQUALITY_PREDS NUMBER

EQUIJOIN_PREDS NUMBER

NONEQUIJOIN_PREDS

NUMBER

RANGE_PREDS NUMBER

LIKE_PREDS NUMBER

NULL_PREDS NUMBER

TIMESTAMP DATE COL_USAGE$ is Updated when statements are parsed Reset when statistics are gathered for table

Page 28: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

28

© 2010 Julian Dyke juliandyke.com

DBMS_STATSHistograms Summary Do not collect histograms if not necessary

Expensive to collect

Check accuracy of histograms Watch for columns with high proportion of NULL values Watch for highly skewed columns

Height-balanced histograms Limited use if column is not highly skewed

Object oriented designs rarely work with histograms

Using histograms introduces bind variable peeking issues

Page 29: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

29

© 2010 Julian Dyke juliandyke.com

DBMS_STATSLocking Statistics Statistics can be locked for schemas, tables, and partitions

LOCK_SCHEMA_STATS / UNLOCK_SCHEMA_STATS LOCK_TABLE_STATS / UNLOCK_TABLE_STATS LOCK_PARTITION_STATS / UNLOCK_PARTITION_STATS

Possible values for STATTYPE are NULL, DATA, CACHE and ALL

By default GATHER procedures will not overwrite locked statistics Specify FORCE => TRUE to overwrite

Statistics locking reported in STATTYPE_LOCKED column in DBA_TAB_STATISTICS DBA_IND_STATISTICS

dbms_stats.lock_table_stats (

ownname => 'USER1',tabname => 'T1',stattype => 'ALL'

);

Page 30: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

30

© 2010 Julian Dyke juliandyke.com

DBMS_STATSDefault Parameters In Oracle 10.1 and above default parameters can be specified System-wide defaults can be set for

AUTOSTATS_TARGET can be ALL collect statistics for all objects in the database ORACLE collect statistics for all Oracle-owned objects AUTO determine which objects need new statistics

Column Name Factory Default

CASCADE DBMS_STATS.AUTO_CASCADE

DEGREE NULL

ESTIMATE_PERCENT DBMS_STATS.AUTO_SAMPLE_SIZE

METHOD_OPT FOR ALL COLUMNS SIZE AUTO

NO_INVALIDATE DBMS_STATS.AUTO_INVALIDATE

GRANULARITY AUTO

AUTOSTATS_TARGET AUTO

Page 31: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

31

© 2010 Julian Dyke juliandyke.com

DBMS_STATSDefault Parameters To set default parameters use SET_PARAM:

dbms_stats.set_param ('ESTIMATE_PERCENT','NULL');

Sets the default to COMPUTE statistics

dbms_stats.set_param ('ESTIMATE_PERCENT',NULL);

Restores factory default (DBMS_STATS.AUTO_SAMPLE_SIZE)

dbms_stats.reset_param_defaults;

Take care with NULL values For example:

dbms_stats.set_param (pname => 'CASCADE',pval => TRUE);

To restore all factory default parameters use:

To check default parameters use GET_PARAM e.g.:

SELECT dbms_stats.get_param (pname => 'CASCADE') FROM dual;

Page 32: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

32

© 2010 Julian Dyke juliandyke.com

ANALYZEversus

DBMS_STATS

Page 33: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

33

© 2010 Julian Dyke juliandyke.com

ANALYZE versus DBMS_STATSDifferences ANALYZE updates the following columns in DBA_TAB_STATISTICS

EMPTY_BLOCKS AVG_SPACE

DBMS_STATS sets these columns to 0

Tables AVG_ROW_LEN differs - e.g.:

Indexes No obvious differences between ANALYZE and DBMS_STATS

Columns AVG_COL_LEN differs - e.g.:

ANALYZE 43

DBMS_STATS 39

ANALYZE 4

DBMS_STATS 5

Page 34: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

34

© 2010 Julian Dyke juliandyke.com

ANALYZE versus DBMS_STATSDifferences ANALYZE <table> gathers statistics for related indexes

Prior to Oracle 10.1 DBMS_STATS requires CASCADE => TRUE

For empty indexes ANALYZE sets BLEVEL to 0 DBMS_STATS sets BLEVEL > 0

Page 35: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

35

© 2010 Julian Dyke juliandyke.com

ANALYZE versus DBMS_STATSSummary Use ANALYZE to

Collect index statistics without updating data dictionary Identify candidates for index coalesce/rebuild Identify candidates for index compression Identify tables containing excessive chained rows

Use DBMS_STATS Gather statistics on tables / indexes

Do not mix ANALYZE / DBMS_STATS

Page 36: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

36

© 2010 Julian Dyke juliandyke.com

SystemStatistics

Page 37: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

37

© 2010 Julian Dyke juliandyke.com

System StatisticsIntroduction System statistics were introduced in Oracle 9.0.1

Subroutines are: GATHER_SYSTEM_STATS DELETE_SYSTEM_STATS GET_SYSTEM_STATS SET_SYSTEM_STATS EXPORT_SYSTEM_STATS IMPORT_SYSTEM_STATS RESTORE_SYSTEM_STATS

System statistics are stored in SYS.AUX_STATS$

Page 38: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

38

© 2010 Julian Dyke juliandyke.com

System StatisticsWorkload versus No Workload Statistics Oracle 10.1 and above supports:

noworkload statistics - default values supplied during database creation workload statistics - collected from representative workload

Workload statistics include: CPUSPEED - CPU speed SREADTIM - Single block read time in milliseconds MREADTIM - Multi block read time in milliseconds MBRC - Multi block read count MAXTHR - Maximum I/O system throughput (parallel execution only) SLAVETHR - Average slave I/O throughput (parallel execution only)

No workload statistics include: CPUSPEEDNW - CPU speed IOSEEKTIM - IO Seek Time IOTFRSPEED - IO Transfer Speed

Page 39: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

39

© 2010 Julian Dyke juliandyke.com

System StatisticsExample

dbms_stats.create_stat_table ('SYS','OLTP_STATS');

dbms_stats.gather_system_stats (

gathering_mode => 'INTERVAL',interval => 60, -- 60 secondsstattab => OLTP_STATS',statid => 'OLTP'

);

Gather system statistics for a typical period using:

Import system statistics into AUX_STATS$ using:

dbms_stats.import_system_stats (

stattab => OLTP_STATS',statid => 'OLTP',statown => 'SYS'

);

Create a statistics table using:

Page 40: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

40

© 2010 Julian Dyke juliandyke.com

System StatisticsSummary Enable system statistics for single instance databases

Usually improve execution plans

Consider carefully before enabling system statistics in RAC databases System statistics are database-specific Watch for asymmetric nodes

Hardware differences Service configuration

System statistics are: Difficult to monitor Very difficult to update / remove

If exporting object statistics to another system for testing: Remember to export system statistics

Page 41: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

41

© 2010 Julian Dyke juliandyke.com

AutomaticStatisticsCollection

Page 42: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

42

© 2010 Julian Dyke juliandyke.com

Automatic Statistics CollectionIntroduction Oracle 10.1 and above

Statistics collected during Maintenance Window Monday - Friday 22:00 to 06:00 Saturday / Sunday All day

Note that weekend window effectively starts at 06:00 on Saturday morning

Scheduler job GATHER_STATS_JOB

Scheduler job class AUTO_TASKS_JOB_CLASS

Scheduler windows WEEKNIGHT_WINDOW WEEKEND_WINDOW

Scheduler window group MAINTENANCE_WINDOW_GROUP

Page 43: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

43

© 2010 Julian Dyke juliandyke.com

StatisticsHistory

Page 44: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

44

© 2010 Julian Dyke juliandyke.com

Statistics HistoryIntroduction In Oracle 10.1 and above, existing statistics are stored in the data dictionary

when new statistics are collected

Statistics can be restored using: RESTORE_DATABASE_STATS RESTORE_DICTIONARY_STATS RESTORE_FIXED_OBJECTS_STATS RESTORE_SCHEMA_STATS RESTORE_SYSTEM_STATS RESTORE_TABLE_STATS

Statistics history for tables only is reported in DBA_TAB_STATS_HISTORY

SELECT stats_update_timeFROM dba_tab_stats_historyWHERE owner = 'USER1'AND table_name = 'T1';

12-FEB-09 04.36.32.997000 PM +00:00

Page 45: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

45

© 2010 Julian Dyke juliandyke.com

Statistics HistoryOptimizer Statistics Operations Statistics gathering operations are reported in DBA_OPTSTAT_OPERATIONS

SELECT operation, target, start_time, end_timeFROM dba_optstat_operationsORDER BY start_time;

gather_database_stats(auto) 07-FEB09 06.00.03 07-FEB-09 06.01.52gather_database_stats(auto) 09-FEB09 10.00.03 09-FEB-09 10.03.37gather_database_stats(auto) 10-FEB09 10.00.03 10-FEB-09 10.02.01

DBA_OPTSTAT_OPERATIONS includes: gather_database_stats(auto) gather_schema_stats

DBA_OPTSTAT_OPERATIONS does not include: gather_table_stats gather_index_stats

Page 46: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

46

© 2010 Julian Dyke juliandyke.com

Statistics HistoryData Dictionary Tables Historic statistics are stored in tables created by

$ORACLE_HOME/rdbms/admin/catost.sql

Tables created are: WRI$_OPTSTAT_TAB_HISTORY WRI$_OPTSTAT_IND_HISTORY WRI$_OPTSTAT_HISTHEAD_HISTORY WRI$_OPTSTAT_HISTGRM_HISTORY WRI$_OPTSTAT_AUX_HISTORY WRI$_OPTSTAT_OPR OPTSTAT_HIST_CONTROL$

Page 47: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

47

© 2010 Julian Dyke juliandyke.com

Statistics HistoryRetention Period To check statistics history retention period use:

SELECT dbms_stats.get_stats_history_retentionFROM dual;

Default is 31 days

To check earliest historic statistics use:

SELECT dbms_stats.get_stats_history_availabilityFROM dual;

12-JAN-09 11.17.50.176000000 PM +00:00

To set statistics history retention period to 90 days:

dbms_stats.alter_stats_history_retention(

retention => 90);

Page 48: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

48

© 2010 Julian Dyke juliandyke.com

Statistics HistorySummary Statistics history rows contain previous values for optimizer statistics

Statistics history does not include current value SAVTIME column is time row was written ANALYZETIME column is time statistics were analyzed SAVTIME != ANALYZETIME

ANALYZE does not update statistics history

[UN]LOCK_TABLE_STATS do update statistics history

Page 49: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

49

© 2010 Julian Dyke juliandyke.com

ManualStatistics

Page 50: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

50

© 2010 Julian Dyke juliandyke.com

Setting Table StatisticsIntroduction Table statistics can be set manually using SET_TABLE_STATS

Values can be specified for: NUMROWS - number of rows NUMBLKS - number of blocks AVGRLEN - average row length

Page 51: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

51

© 2010 Julian Dyke juliandyke.com

Setting Table StatisticsExample (1 of 4)

DECLAREl_numrows NUMBER;l_numblks NUMBER;l_avgrlen NUMBER;l_flags NUMBER;

l_total_blocks NUMBER;l_total_bytes NUMBER;l_unused_blocks NUMBER;l_unused_bytes NUMBER;l_last_used_extent_file_id NUMBER;l_last_used_extent_block_id NUMBER;l_last_used_block NUMBER;

Page 52: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

52

© 2010 Julian Dyke juliandyke.com

Setting Table Statistics Example (2 of 4)

BEGINdbms_stats.get_table_stats(

ownname => 'GP',tabname => 'CAR',numrows => l_numrows,numblks => l_numblks,avgrlen => l_avgrlen,

);

l_numrows := 0;l_numblks := 0;

SELECT COUNT(*) INTO l_numrows FROM gp.car;

Page 53: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

53

© 2010 Julian Dyke juliandyke.com

Setting Table Statistics Example (3 of 4)

dbms_space.unused_space(

segment_owner => 'GP',segment_name => 'CAR',segment_type => 'TABLE',total_blocks => l_total_blocks,total_bytes => l_total_bytes,unused_blocks => l_unused_blocks,unused_bytes => l_unused_bytes,last_used_extent_file_id => l_last_used_extent_file_id,last_used_extent_block_id => l_last_used_extent_block_id,last_used_block => l_last_used_block

);

l_numblks := l_total_blocks;

Page 54: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

54

© 2010 Julian Dyke juliandyke.com

Setting Table Statistics Example (4 of 4)

dbms_stats.set_table_stats(

ownname => 'GP',tabname => 'CAR',numrows => l_numrows,numblks => l_numblks,avgrlen => l_avgrlen

);END;

Page 55: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

55

© 2010 Julian Dyke juliandyke.com

Setting Index StatisticsIntroduction Index statistics can be set manually using SET_INDEX_STATS

Values can be specified for: NUMROWS - number of rows NUMBLKS - number of blocks NUMDIST - number of distinct values AVGLBLK - average leaf blocks per key AVGDBLK - average data blocks per key CLSTFCT - clustering factor INDLEVEL - index level (height)

Use ANALYZE INDEX VALIDATE STRUCTURE to determine values

Page 56: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

56

© 2010 Julian Dyke juliandyke.com

Setting Column StatisticsIntroduction Column statistics can be set manually using SET_COLUMN_STATS

Values can be specified for: DISTCNT - number of distinct values DENSITY - 1 / (number of distinct values) NULLCNT - number of NULL values Low and high values Histograms

Note that DISTCNT usage differs for columns with histograms

Page 57: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

57

© 2010 Julian Dyke juliandyke.com

Setting Column Statistics Data Types Requires additional data types declared in DBMS_STATS package See $ORACLE_HOME/rdbms/admin/dbmsstat.sql

TYPE numarray IS VARRAY(256) OF NUMBER;

TYPE chararray IS VARRAY(256) OF VARCHAR2(4000);

TYPE statrec IS RECORD(

EPC NUMBER,MINVAL RAW(2000),MAXVAL RAW(2000),BKVALS NUMARRAY,NOVALS NUMARRAY,CHVALS CHARARRAY,EAVS NUMBER

)

Page 58: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

58

© 2010 Julian Dyke juliandyke.com

Setting Column Statistics Example (1 of 3)

PROCEDURE copy_col_stats

(p_owner VARCHAR2,p_table_name VARCHAR2) ISl_row DBA_TAB_COLUMNS%ROWTYPE;l_statrec dbms_stats.statrec;l_numvals dbms_stats.numarray := dbms_stats.numarray();l_charvals dbms_stats.chararray := dbms_stats.chararray();l_datevals dbms_stats.datearray := dbms_stats.datearray();

CURSOR c1 RETURN DBA_TAB_COLUMNS%ROWTYPE ISSELECT *FROM dba_tab_columnsWHERE owner = p_ownerAND table_name = p_table_name;

BEGINl_numvals.extend(2);l_charvals.extend(2);l_datevals.extend(2);

OPEN c1;LOOP

FETCH c1 INTO l_row;EXIT WHEN c1%NOTFOUND;

Page 59: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

59

© 2010 Julian Dyke juliandyke.com

Setting Column Statistics Example (2 of 3)

IF l_row.num_buckets IS NOT NULL THENl_statrec.epc := 2;l_statrec.bkvals := NULL;l_numvals(1) := NULL; l_numvals(2) := NULL;l_charvals(1) := NULL; l_charvals(2) := NULL;l_datevals(1) := NULL; l_datevals(2) := NULL;

IF l_row.column_name = 'COL1' THENl_numvals(1) := get_min_col1 (p_owner,p_table_name);l_numvals(2) := get_max_col2 (p_owner,p_table_name);DBMS_STATS.PREPARE_COLUMN_VALUES (l_statrec,l_numvals);

ELSIF l_row.column_name = 'COL2' THENl_datevals(1) := TO_DATE (v_target_date,'YYYYMMDD');l_datevals(2) := TO_DATE (v_target_date,'YYYYMMDD');DBMS_STATS.PREPARE_COLUMN_VALUES (l_statrec,l_datevals);

ELSIF l_row.column_name = 'COL3' THENl_charvals(1) := get_min_col3 (p_owner,p_table_name);l_charvals(2) := get_max_col3 (p_owner,p_table_name);DBMS_STATS.PREPARE_COLUMN_VALUES (l_statrec,l_charvals);

END IF;

Page 60: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

60

© 2010 Julian Dyke juliandyke.com

Setting Column Statistics Example (3 of 3) Setting minimum and maximum values (without histograms)

DBMS_STATS.SET_COLUMN_STATS(

ownname => p_owner,tabname => p_table_name,colname => l_row.column_name,distcnt => l_row.num_distinct,density => l_row.density,nullcnt => l_row.num_nulls,srec => l_statrec,avgclen => l_row.avg_col_len

);END IF;END LOOP;CLOSE c1;

END;

Page 61: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

61

© 2010 Julian Dyke juliandyke.com

Setting Column Statistics - HistogramsExample (1 of 2)

DECLAREl_statrec dbms_stats.statrec;l_charvals dbms_stats.chararray := dbms_stats.chararray ();l_bkvals dbms_stats.numarray := dbms_stats.numarray ();

BEGINl_charvals.extend (11);l_bkvals.extend (11);

l_charvals(1) := 'MSCH'; l_bkvals(1) := 91;l_charvals(2) := 'APRO'; l_bkvals(2) := 51;l_charvals(3) := 'ASEN'; l_bkvals(3) := 41;l_charvals(4) := 'NMAN'; l_bkvals(4) := 31;l_charvals(5) := 'JSTE'; l_bkvals(5) := 27;l_charvals(6) := 'NLAU'; l_bkvals(6) := 25;l_charvals(7) := 'JCLA'; l_bkvals(7) := 25;l_charvals(8) := 'NPIQ'; l_bkvals(8) := 23;l_charvals(9) := 'FALO'; l_bkvals(9) := 22;l_charvals(10) := 'DHIL'; l_bkvals(10) := 22;l_charvals(11) := 'MHAK'; l_bkvals(11) := 20;

Page 62: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

62

© 2010 Julian Dyke juliandyke.com

Setting Column Statistics - HistogramsExample (2 of 2)

l_statrec.epc := 11;l_statrec.bkvals := l_bkvals;l_statrec.eavs := 0;

DBMS_STATS.PREPARE_COLUMN_VALUES (l_statrec,l_charvals);

DBMS_STATS.SET_COLUMN_STATS(

ownname => 'GP',tabname => 'CAR',colname => 'DRIVER_KEY',distcnt => 11,density => 0.00210084, -- 1 / 476 rows

nullcnt => 0,srec => l_statrec,avgclen => 4

);END;/

Page 63: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

63

© 2010 Julian Dyke juliandyke.com

Partition Statistics

Page 64: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

64

© 2010 Julian Dyke juliandyke.com

Partition Statistics Introduction Partition statistics are reported by:

DBA_TABLES DBA_TAB_PARTITIONS DBA_TAB_STATISTICS DBA_TAB_SUBPARTITIONS (Oracle 10.1 and above)

Indexes DBA_INDEXES DBA_IND_PARTITIONS DBA_IND_STATISTICS DBA_IND_SUBPARTITIONS (Oracle 10.1 and above)

Columns DBA_TAB_COL_STATISTICS DBA_PART_COL_STATISTICS DBA_SUBPART_COL_STATISTICS

Histograms DBA_TAB_HISTOGRAMS DBA_PART_HISTOGRAMS DBA_SUBPART_HISTOGRAMS

Page 65: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

65

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (1 of 12) Create a range partitioned table containing data for last four seasons

CREATE TABLE car3PARTITION BY RANGE (season_key)(

PARTITION p2005 VALUES LESS THAN ('2006'),PARTITION p2006 VALUES LESS THAN ('2007'),PARTITION p2007 VALUES LESS THAN ('2008'),PARTITION p2008 VALUES LESS THAN ('2009')

)AS SELECT * FROM carWHERE season_key >= '2005';

CREATE INDEX car3_i1 ON car3(season_key,race_key,position) LOCAL;

dbms_stats.gather_table_stats(

ownname => 'GP',tabname => 'CAR3',estimate_percent => NULL,cascade => TRUE

);

Page 66: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

66

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (2 of 12) Table Statistics

SELECT num_rows,blocks,avg_row_len FROM dba_tablesWHERE owner = 'GP' AND table_name = 'CAR3';

SELECT partition_name,num_rows,blocks,avg_row_len FROM dba_tab_partitionsWHERE table_owner = 'GP' AND table_name = 'CAR3';

NUM_ROWS BLOCKS AVG_ROW_LEN

1518 24 37

PARTITION_NAME NUM_ROWS BLOCKS AVG_ROW_LEN

P2005 380 6 36

P2006 396 6 38

P2007 374 6 37

P2008 368 6 37

Page 67: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

67

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (3 of 12) Index Statistics

SELECT blevel, leaf_blocks, distinct_keys, clustering_factor, num_rowsFROM dba_indexesWHERE owner = 'GP' AND index_name = 'CAR3_I1';

BLEVEL LEAF_BLOCKS DIST KEYS CLUFAC NUM_ROWS

1 8 1518 15 1518

PARTITION_NAME BLEVEL LEAF_BLOCKS DIST KEYS CLUFAC NUM_ROWS

P2005 1 2 380 3 380

P2006 1 2 396 3 396

P2007 1 2 374 5 374

P2008 1 2 368 4 368

SELECT partition_name, blevel, leaf_blocks, distinct_keys, clustering_factor, num_rows

FROM dba_ind_partitionsWHERE index_owner = 'GP' AND index_name = 'CAR3_I1';

Page 68: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

68

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (4 of 12) Add a new partition for 2009 season

ALTER TABLE car3ADD PARTITION p2009 VALUES LESS THAN ('2010');

dbms_stats.gather_table_stats(

ownname => 'GP',tabname => 'CAR3',estimate_percent => NULL,cascade => TRUE

);

Gather statistics again

Page 69: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

69

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (5 of 12) Table Statistics

SELECT num_rows,blocks,avg_row_len FROM dba_tablesWHERE owner = 'GP' AND table_name = 'CAR3';

SELECT partition_name,num_rows,blocks,avg_row_len FROM dba_tab_partitionsWHERE table_owner = 'GP' AND table_name = 'CAR3';

NUM_ROWS BLOCKS AVG_ROW_LEN

1518 24 37

PARTITION_NAME NUM_ROWS BLOCKS AVG_ROW_LEN

P2005 380 6 36

P2006 396 6 38

P2007 374 6 37

P2008 368 6 37

P2009 0 0 0

Page 70: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

70

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (6 of 12) Index Statistics

SELECT blevel, leaf_blocks, distinct_keys, clustering_factor, num_rowsFROM dba_indexesWHERE owner = 'GP' AND index_name = 'CAR3_I1';

BLEVEL LEAF_BLOCKS DIST KEYS CLUFAC NUM_ROWS

1 8 1518 15 1518

PARTITION_NAME BLEVEL LEAF_BLOCKS DIST KEYS CLUFAC NUM_ROWS

P2005 1 2 380 3 380

P2006 1 2 396 3 396

P2007 1 2 374 5 374

P2008 1 2 368 4 368

P2009 0 0 0 0 0

SELECT partition_name, blevel, leaf_blocks, distinct_keys, clustering_factor, num_rows

FROM dba_ind_partitionsWHERE index_owner = 'GP' AND index_name = 'CAR3_I1';

Page 71: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

71

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (7 of 12) Copy table statistics from 2008 to 2009 partitions

dbms_stats.copy_table_stats(

ownname => 'GP',tabname => 'CAR3',srcpartname => 'P2008',dstpartname => 'P2009'

);

Page 72: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

72

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (8 of 12) Table Statistics

SELECT num_rows,blocks,avg_row_len FROM dba_tablesWHERE owner = 'GP' AND table_name = 'CAR3';

SELECT partition_name,num_rows,blocks,avg_row_len FROM dba_tab_partitionsWHERE table_owner = 'GP' AND table_name = 'CAR3';

NUM_ROWS BLOCKS AVG_ROW_LEN

1518 24 37

PARTITION_NAME NUM_ROWS BLOCKS AVG_ROW_LEN

P2005 380 6 36

P2006 396 6 38

P2007 374 6 37

P2008 368 6 37

P2009 368 6 37

Page 73: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

73

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (9 of 12) Index Statistics

SELECT blevel, leaf_blocks, distinct_keys, clustering_factor, num_rowsFROM dba_indexesWHERE owner = 'GP' AND index_name = 'CAR3_I1';

BLEVEL LEAF_BLOCKS DIST KEYS CLUFAC NUM_ROWS

1 8 1518 15 1518

PARTITION_NAME BLEVEL LEAF_BLOCKS DIST KEYS CLUFAC NUM_ROWS

P2005 1 2 380 3 380

P2006 1 2 396 3 396

P2007 1 2 374 5 374

P2008 1 2 368 4 368

P2009 1 2 368 4 368

SELECT partition_name, blevel, leaf_blocks, distinct_keys, clustering_factor, num_rows

FROM dba_ind_partitionsWHERE index_owner = 'GP' AND index_name = 'CAR3_I1';

Page 74: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

74

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (10 of 12) Copy rows from 2008 to 2009. For example:

INSERT INTO car3SELECT

'2009',race_key,driver_key,team_key,engine_key,position,laps_completed,classification_key,notes,driver_points,team_points

FROM gp.car3WHERE season_key = '2008';

Statistics are unchanged

Page 75: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

75

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (11 of 12) Execution plans for statement against 2008 and 2009 partitions:

SELECT SUM(team_points) FROM gp.car3WHERE season_key = '2009';

0 SELECT STATEMENT1 0 SORT AGGREGATE2 1 PARTITION RANGE (SINGLE)3 2 TABLE ACCESS (BY INDEX ROWID) OF 'CAR3'4 3 INDEX (RANGE SCAN) OF 'CAR3_I1'

SELECT SUM(team_points) FROM gp.car3WHERE season_key = '2008';

0 SELECT STATEMENT1 0 SORT AGGREGATE2 1 PARTITION RANGE (SINGLE)3 2 TABLE ACCESS (FULL) OF 'CAR3'

Plans are different even though statistics and data are theoretically identical

Page 76: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

76

© 2010 Julian Dyke juliandyke.com

Partition StatisticsExample (12 of 12) In Oracle 10.2.0.4 column values are not updated by COPY_TABLE_STATS

SELECT partition_name,low_value,high_valueFROM dba_part_col_statisticsWHERE owner = 'GP'AND table_name = 'CAR3'AND column_name = 'SEASON_KEY';

PARTITION_NAME LOW_VALUE HIGH_VALUE

P2005 0x32303035 (2005)

0x32303035 (2005)

P2006 0x32303036 (2006)

0x32303036 (2006)

P2007 0x32303037 (2007)

0x32303037 (2007)

P2008 0x32303038 (2008)

0x32303038 (2008)

P2009 0x32303038 (2008)

0x32303038 (2008)

Caused by bug 5643297 - only affects 10.2.0.4 Fixed in patch 7381308

includes fixes for COPY_TABLE_STATS and APPROX_GLOBAL

Page 77: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

77

© 2010 Julian Dyke juliandyke.com

Partition StatisticsSummary Range-partitioning

Only collect statistics for partitions undergoing change Specify partition names and GRANULARITY parameter to restrict

partitions that are analyzed

Consider setting statistics manually for new partitions COPY_STATS has limited functionality Watch for changing high values

Use DBMS_STATS NO_INVALIDATE option ANALYZE invalidates all cursors referencing table being analyzed Can result in hard-parse rates approaching 100%

Page 78: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

78

© 2010 Julian Dyke juliandyke.com

Oracle 11gEnhancements

Page 79: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

79

© 2010 Julian Dyke juliandyke.com

StatisticsPreferences

Page 80: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

80

© 2010 Julian Dyke juliandyke.com

Oracle 11g EnhancementsStatistics Preferences In Oracle 10g preferences are:

set using SET_PARAM reported by GET_PARAM stored in SYS.OPTSTAT_HIST_CONTROL$

In Oracle 11.1 and above preferences are: set using:

SET_TABLE_PREFS SET_SCHEMA_PREFS SET_DATABASE_PREFS SET_GLOBAL_PREFS

reported by GET_PREFS DBA_TAB_STAT_PREFS

stored in SYS.OPTSTAT_USER_PREFS$

In Oracle 11.1 and above global preferences can be reset using RESET_GLOBAL_PREF_DEFAULTS

Page 81: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

81

© 2010 Julian Dyke juliandyke.com

Oracle 11g EnhancementsStatistics Preferences

In Oracle 10g preferences can be set for: CASCADE DEGREE ESTIMATE_PERCENT METHOD_OPT NO_INVALIDATE GRANULARITY

In Oracle 11g preferences can also be set for: PUBLISH - if TRUE publish statistics; if FALSE store as pending STALE_PERCENT - threshold level at which statistics considered stale INCREMENTAL - if TRUE collect incremental global partition statistics

Allow automatic statistics collection to be customized for individual objects For example heavily skewed data distributions

Can be set at table, schema, database and global level

Page 82: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

82

© 2010 Julian Dyke juliandyke.com

Oracle 11g EnhancementsStatistics Preferences Delete preferences using:

DELETE_TABLE_PREFS DELETE_SCHEMA_PREFS DELETE_DATABASE_PREFS

Export and import preferences using: EXPORT_TABLE_PREFS / IMPORT_TABLE_PREFS EXPORT_SCHEMA_PREFS / IMPORT_SCHEMA_PREFS EXPORT_DATABASE_PREFS / IMPORT_DATABASE_PREFS

Page 83: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

83

© 2010 Julian Dyke juliandyke.com

PendingStatistics

Page 84: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

84

© 2010 Julian Dyke juliandyke.com

Oracle 11g EnhancementsPending Statistics In Oracle 11.1 and above statistics can be

Published - current statistics used by optimizer Pending - private statistics not yet published

In Oracle 11.1 statistics for a set of objects can be collected as an atomic transaction

Published at same time Avoids inconsistencies

PUBLISH mode can be set at the following levels Global Database Schema Table

Page 85: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

85

© 2010 Julian Dyke juliandyke.com

Oracle 11g EnhancementsPending Statistics To defer publication of all statistics collected by USER1 use:

ALTER SESSION optimizer_use_pending_statistics = TRUE;

To make pending statistics permanently available to the optimizer use:

dbms_stats.publish_pending_statistics(

ownname => 'USER1',tabname => NULL

);

Statistics can be published at database, schema or table level

To delete pending statistics use DELETE_PENDING_STATS

To export pending statistics use EXPORT_PENDING_STATS There is no corresponding import procedure

To make pending statistics temporarily available to the optimizer use:

dbms_stats.set_schema_prefs ('USER1','PUBLISH','FALSE');

Page 86: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

86

© 2010 Julian Dyke juliandyke.com

ExtendedStatistics

Page 87: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

87

© 2010 Julian Dyke juliandyke.com

Oracle 11g EnhancementsExtended Statistics Extended statistics attempt to reflect true selectivity of data

There are two types: multi-column statistics expression statistics

Extended statistics use the following procedures: CREATE_EXTENDED_STATS DROP_EXTENDED_STATS SHOW_EXTENDED_STATS_NAME

Page 88: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

88

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Multi-Column Statistics In Oracle 11g the following statistics can be gathered on multiple columns in a

table (column groups):

Number of distinct values Density Number of nulls Frequency histograms

Multicolumn statistics Appear to work for frequency histograms

<= 254 combinations of values Do not appear to work for height-based histograms

> 254 combinations of values

Page 89: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

89

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Multi-Column Statistics

SELECT COUNT(*) FROM gp.carWHERE team_key = 'FER'AND engine_key = 'FER';

COUNT(*)1410

Id

Operation Name Rows Bytes Cost (%CPU)

Time

0 SELECT STATEMENT 35 (100)

1 SORT AGGREGATE 1 13

2 TABLE ACCESS FULL CAR 137 1781 35 (0) 00:00:01

Incorrect Cardinality

Page 90: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

90

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Multi-Column Statistics

BEGINdbms_stats.gather_table_stats(

ownname => 'GP',tabname => 'CAR',estimate_percent => NULL,method_opt => 'FOR ALL COLUMNS SIZE 254 '||'FOR COLUMNS (TEAM_KEY,ENGINE_KEY) SIZE 254'

);END;

DECLAREl_extension_name VARCHAR2(30);

BEGINl_extension_name := dbms_stats.create_extended_stats(

ownname => 'GP',tabname => 'CAR',extension => '(team_key,engine_key)'

);END;

Page 91: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

91

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Multi-Column Statistics

Id

Operation Name Rows Bytes Cost (%CPU)

Time

0 SELECT STATEMENT 35 (100)

1 SORT AGGREGATE 1 13

2 TABLE ACCESS FULL CAR 1410 18330 35 (0) 00:00:01

SELECT COUNT(*) FROM gp.carWHERE team_key = 'FER'AND engine_key = 'FER';

COUNT(*)1410

Correct Cardinality

Page 92: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

92

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Multi-Column Statistics

Extension Name Extension

SYS_STUWIHETSRHT#5P210Z$AO1ON9

("TEAM_KEY","ENGINE_KEY")

SELECT extension_name,extensionFROM dba_stat_extensionsWHERE owner = 'GP'AND table_name = 'CAR';

Page 93: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

93

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Multi-Column Statistics

INTCOL#

COL# NAME

1 1 SEASON_KEY

2 2 RACE_KEY

3 3 DRIVER_KEY

4 4 TEAM_KEY

5 5 ENGINE_KEY

6 6 POSITION

7 7 LAPS_COMPLETED

8 8 CLASSIFICATION_KEY

9 9 NOTES

10 0 SYS_STUWIHETSRHT#5P210Z$AO1ON9

SELECT c.intcol#,c.col#,c.nameFROM sys.col$ c, sys.obj$ o, sys.user$ uWHERE c.obj# = o.obj#AND o.name = 'CAR'AND o.owner# = u.user#AND u.name = 'GP';

New Virtual Column in Tablefor Multi-Column

Statistics

Page 94: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

94

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Expression Statistics

CREATE OR REPLACE FUNCTION points(season_key VARCHAR2,race_key NUMBER,position NUMBER)RETURN NUMBERDETERMINISTIC IS

l_result NUMBER;BEGIN

l_result := CASE positionWHEN 1 THEN 10WHEN 2 THEN 8WHEN 3 THEN 6WHEN 4 THEN 5WHEN 5 THEN 4WHEN 6 THEN 3WHEN 7 THEN 2WHEN 8 THEN 1ELSE 0

END;RETURN l_result;

END;

Note: The real algorithm is MUCH more complicated for various reasons including:

• changes to number of points awarded

• disqualifications, penalties etc

• differences between drivers and team championship points systems

Page 95: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

95

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Expression Statistics

SELECT COUNT(*) FROM gp.car WHERE POINTS (season_key,race_key,position) = 10;

COUNT(*)709

Id

Operation Name Rows Bytes Cost (%CPU)

Time

0 SELECT STATEMENT 38 (100)

1 SORT AGGREGATE 1 13

2 TABLE ACCESS FULL CAR 177 4248 38 (0) 00:00:01

Incorrect Cardinality

Page 96: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

96

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Expression Statistics

BEGINdbms_stats.gather_table_stats(

ownname => 'GP',tabname => 'CAR',estimate_percent => NULL,method_opt => 'FOR ALL COLUMNS SIZE 254 '||'FOR COLUMNS (points(season_key,race_key,position)) SIZE 254'

);END;

DECLAREl_extension_name VARCHAR2(30);

BEGINl_extension_name := dbms_stats.create_extended_stats(

ownname => 'GP',tabname => 'CAR',extension => '(points(season_key,race_key,position))'

);END;

Page 97: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

97

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Expression Statistics

SELECT COUNT(*) FROM gp.car WHERE POINTS (season_key,race_key,position) = 10;

COUNT(*)709

Id

Operation Name Rows Bytes Cost (%CPU)

Time

0 SELECT STATEMENT 38 (100)

1 SORT AGGREGATE 1 13

2 TABLE ACCESS FULL CAR 709 19143 38 (0) 00:00:01

Correct Cardinality

Page 98: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

98

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Incremental Statistics For partitioned tables statistics can be collected:

For sub-partitions For partitions Globally

Global statistics should reflect underlying partitioned statistics

Prior to Oracle 11.1 calculation of global statistics required full table scan of each partition in table

For many applications using range partitioning only the most recent partition is subject to change

Older partitions contain historical data

Page 99: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

99

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Incremental Statistics For example:

CREATE TABLE car4PARTITION BY RANGE (season_key)(

PARTITION p2006 VALUES LESS THAN ('2005'),PARTITION p2007 VALUES LESS THAN ('2006'),PARTITION p2008 VALUES LESS THAN ('2007'),PARTITION p2009 VALUES LESS THAN ('2008')

)AS SELECT * FROM carWHERE season_key >= '2005';

CREATE INDEX i_car4_1 ON carp(season_key,race_key,position) LOCAL;

INSERT INTO car4 SELECT * FROM car WHERE season_key BETWEEN 2006 AND 2009;

Create table with

partitions for four years

data

Insert data

Page 100: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

100

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Incremental Statistics Gather statistics

DBMS_STATS.GATHER_TABLE_STATS(

ownname => 'GP',tabname => 'CAR4'

);

Requires full table scan for each partition

Full Table Scan2006

Full Table Scan2007

Full Table Scan2008

Full Table Scan2009

Page 101: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

101

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Incremental Statistics Update data in one partition:

DBMS_STATS.GATHER_TABLE_STATS(

ownname => 'GP',tabname => 'CAR4'

);

Still requires full table scan for each partition

Full Table Scan2006

Full Table Scan2007

Full Table Scan2008

Full Table Scan2009

UPDATE car4 SET team_points = driver_pointsWHERE season_key = '2009';

Gather table statistics again:

Page 102: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

102

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Incremental Statistics In Oracle 11.1 and above statistics can be gathered incrementally for

partitioned tables

To gather incremental statistics on a specific table INCREMENTAL and PUBLISH preferences for table must be TRUE ESTIMATE_PERCENT must be AUTO_SAMPLE_SIZE GRANULARITY must be AUTO

For each partition a synopsis is created Contains data about distinct values for each column in partition Stored in

SYS.WRI$_OPTSTAT_SYNOPSIS_HEAD$ SYS.WRI$_OPTSTAT_SYNOPSIS$

If a partition has not been modified synopsis can be used to calculate global statistics

Synopsis must be generated for all partitions first time statistics are gathered after incremental statistics are enabled

Page 103: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

103

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Incremental Statistics Set INCREMENTAL preference to TRUE for table:

BEGINDBMS_STATS.SET_TABLE_PREFS(

ownname => 'GP',tabname => 'CAR4',pname => 'INCREMENTAL',pvalue => 'TRUE'

);END;/

Gather table statistics again to generate synopsis for each partition

DBMS_STATS.GATHER_TABLE_STATS(

ownname => 'GP',tabname => 'CAR4'

);

All partitions will be scanned first

time to create synopsis

Page 104: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

104

© 2010 Julian Dyke juliandyke.com

Oracle 11g Enhancements Incremental Statistics Update data in one partition:

DBMS_STATS.GATHER_TABLE_STATS(

ownname => 'GP',tabname => 'CARP'

);

Uses synopsis for unmodified partitions Requires full table scan for modified partition

2006

2007

2008

Full Table Scan2009

UPDATE car4 SET team_points = driver_pointsWHERE season_key = '2009';

Gather table statistics again:

Synopsis

Synopsis

Synopsis

Page 105: 1 © 2010 Julian Dyke juliandyke.com Optimizer Statistics Julian Dyke Independent Consultant Web Version.

105

© 2010 Julian Dyke juliandyke.com

Thanks to the following for corrections:

[email protected]

Greg Rahn Tony Hasler