Guiding Practices for Gathering Database Statistics Martin Widlake Database Architecture, Performance & Training Ora600 Limited http://mwidlake.wordpress.com www.ora600.org.uk ORA00 Ltd 1/45 Abstract • Guiding practices for Database Statistics gathering • The Cost Based Optimizer continues to improve and stats gathering is now more efficient than ever - but it still seems to be that most Oracle Sites struggle with performance issues due to poor stats. It's like the annoying, embarrassing rash that simple won't go away. I will cover the options available and general principles for sorting out the stats issue, which should lead to more stable and good performance ie a more comfortable life . This should calm the annoying rash and give you some potential treatments should it flare up again. ORA600 Ltd 2/45 Who am I and why am I doing this Talk? • 20+ years of Oracle experience, mostly as a developer, development DBA, Architect, Performance guy. • Tested the CBO under V7.3 and became a cautious advocate of it in V8. Been fighting the issues since! • I keep getting pulled into designing “better” methods of gathering stats for clients and, frankly, I’d rather do other things {thus the presentations and blog posting telling everyone what I know}. • I am of the opinion that, over all the CBO now gets 99% of SQL execution plans good enough, if the stats are good. • Stats gathering can be quite interesting. Honest! ORA600 Ltd 3/45 These slides will be on the UKOUG web site I am going to talk around some slides (the ones with pictures on and key points) and skip over some - as we all get tired of reading powerpoint slides in presentations. The others are there to fill in the chat. Ask questions, Email me mwidlake@btinternet.com mwidlake.wordpress.com ORA600 Ltd 4/45 Quick Quiz • What is the most common version of Oracle you currently use? (8, 9, 10.1, 10.2, 11.1, 11.2) • What is the latest version you use in production? • Who relies on the Automated Stats Collection job on their database? (If “Yes”, have you altered the schedule?) • Who has intermittent performance issues when code goes bad either “over night” or after stats are collected? • Who has a site-crafted stats gathering regime? • (If your site wrote it’s own, did it take 2X, 4X, 8X or more the effort to get right than you expected?). ORA600 Ltd 5/45 Possibly the Single Most Common Cause of Poor Database Performance Poor or missing object statistics are probably the single most common and easily fixed cause of In my poor opinion, the introduction database performance. of the automated stats gathering process with Most issue with individual SQL statements Oracle 10g was probably the single greatest performing poorly are fixed by gathering accurate performance enhancement by Oracle Corp statistics on the tables involved. In the last 15 years. The worst of all situations is to have statistics on a few tables.And The ICost Based Optimiser don’t really like it is invoked and has to use very poor defaults for everything else. Ora 600 Ltd 6/45 Automatic Stats Collection Auto Stats Job Preparation FLUSH_DATABASE_ MONITORING_INFO Global and Table Prefs (stale_pct,est_pct, met_op. Degree..) DBA_TAB_MODIFICATIONS (10% BY DEFAULT) SYS.COL_USAGE$ Data Dictionary Information Existing Statistics OBJ_FILTER_LIST (STALE AND EMPTY) Runs gathers In the scheduled window ORA600 Ltd 7/45 GATHER_DATABASE_STATS_JOB_PROC From the 10g Tuning guide:The GATHER_DATABASE_STATS_JOB_PROC procedure collects statistics on database objects when the object has no previously gathered statistics or the existing statistics are stale because the underlying object has been modified significantly (more than 10% of the rows).The DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC is an internal procedure, but its operates in a very similar fashion to the DBMS_STATS.GATHER_DATABASE_STATS procedure using the GATHER AUTO option. The primary difference is that the DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC procedure prioritizes the database objects that require statistics, so that those objects which most need updated statistics are processed first. This ensures that the most-needed statistics are gathered before the maintenance window closes. That last sentence is the only major change in the 11g documentation. Ora 600 Ltd 8/45 Automated DBMS_STATS Job • If it works for you, then fine, leave it be and work on something else. If it almost works for you, fix the exceptions, leave the main job alone and work on something else. • If you have a VLDB (or you downloaded this as you had an issue with stats gathering) It is almost certainly not good enough for you. • It is an attempt at a single solution to work for every situation and it does not. Even Oracle Corp have admitted, it just simply does not work for VLDBs, it chokes on large objects • Turn it off (maybe leave it running for DICTIONARY stats) and write the replacement. You will write something that does a lot of what this job does. Your replacement will almost certainly be more complex than you initially plan. Sorry. • There is no one single solution to stats gathering that is right for any large, complex system. {Sorry again} ORA600 Ltd 9/45 DBA _TAB_MODIFICATIONS • All inserts, updates, deletes and truncate operations on monitored tables are flushed to this table. So V10 upwards, that is everything. • Under V9 flushed every 3 hours, under V10.1 every 15 minutes, under V10.2/V11 it is not automatically flushed. • It is flushed to by calls to schema/db dbms_stats GATHER calls or by calling DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO It doesgenerally not capture directbut inserts, things that avoid the It• seems accurate I haveappends, witnessed it missing the odd SQL layer. “insert-into-select” statements. And it does not see direct-insert activity. • Increments, including over database restarts. • Row is deleted when stats are gathered on the Table OR PARTITION (and only at the correct level). Ora 600 Ltd 10/45 show_tab_mods OBJ_NAME NO_INS NO_UPD NO_DEL T LAST_FLUSH -- show_tab_mods --------------------------------------- --------- --------- ------ - ---------------- Martin Widlake 11-nov-07 MIDDLEOFFICE.POSITIONLIQUIDATIONAUDIT9,588 0 0 N 080602 10:06:03 -- quick check on recent table changes MIDDLEOFFICE.POSITIONKEEPINGGROUPS2 1 0 N 080602 10:06:03 -- NB flush if want up-to-date info (15 min interval) GATEWAY.TREE_RELATIONS44 0 43 N 080602 10:06:03 set lines 100 pause on COMMHOME.COMM_TRAD_PCTTRAD_BAND4 0 4 N 080602 10:06:03 col obj_name form a50 GATEWAY.INSTRUMENT_INFO2 1 0 N 080602 10:06:03 col no_ins form 9999,999 GATEWAY.TRADINGPERIODPROFILEDATA1 0 1 N 080602 10:06:03 col no_upd form 9999,999 BOBJ_LOGIN.ORDERS-ORDERS_12345678 1,066 9,381 0 N 080531 06:05:03 col no_del form 999,999 DATAFIX.TRADEORD_VOLT2 0 0 N 080531 06:05:03 select table_owner||'.'||table_name||'-'||partition_name obj_name BOBJ_LOGIN.ORDERS_HISTORY-OH_54545454 9,379 0 0 N 080531 06:05:03 ,inserts no_ins DATAFIX.MAXORDERS2 0 0 N 080531 06:05:03 ,updates no_upd ,deletes no_del BOBJ_LOGIN.ORDERAUDIT-ORDERAUDIT23 1375610 0 0 N 080530 10:05:02 ,substr(truncated,1,1) T COMMHOME.COMM_ON_DEPOSIT_H4 0 0 N 080530 10:05:02 ,to_char(timestamp,'YYMMDD hh:mm:ss') 95,449 last_flush GATEWAY.BIN$TnRrf2V98FrgQwrckArwWg==$00 0 N 080530 10:05:02 from dba_tab_modifications GATEWAY.BIN$TnRrf2V38FrgQwrckArwWg==$0882 0 0 N 080530 10:05:02 where timestamp > sysdate -31 GATEWAY.DEALINGRECNMSAI290 5,052 0 N 080530 10:05:02 and table_owner not like 'SYS%' GATEWAY.BIN$TnRkBv02UezgQwrckApR7A==$016,913 0 0 N 080530 10:05:02 order by timestamp desc / clear colu Ora 600 Ltd 11/45 -- mdw 11/05/03 TAB_NAME ANLYZD_ROWS LAST_ANLZD TOT_ROWS CHNGS PCT_C -- mdw 17/01/08 Modified to look at dba_tab_modifications ---------------------------------------------- -------- -----set pause on pages 24 lines 110 pause --------------'Any Key>' GATEWAY.ACCESSGROUPS 4 0 .000 colu anlyzd_rows form 99999,999,999 4 080212 16:03:12 MIDDLEOFFICE.ACCOUNTAUDIT 4,725,464 080512 22:37:16 4,898,302 173,738 .037 colu tot_rows form 99999,999,999 GATEWAY.ACCOUNTBEHAVIOURS 14 080212 16:03:18 14 0 .000 colu tab_name form a30 GATEWAY.ENBZHEERHWV 149,136 080522 22:06:39 150,922 6,156 .041 colu chngs form 99,999,999 DATAFIX.VRHERHHHEHH_08_RBK 17,650 080425 22:00:04 17,650 0 .000 colu pct_c form 999.999 DATAFIX.AFEOUNSFEWS_190505 42,757 071105 22:01:00 42,757 0 .000 select dbta.owner||'.'||dbta.table_name tab_name DATAFIX.ACSFFWEGGEE_310108 182 080131 22:00:03 182 .000 ,dbta.num_rows anlyzd_rows0 MM_AUDIT.EFEFEFGHOME_AUDIT 513,230 080509 22:07:34 526,192 12,962 .025 ,to_char(dbta.last_analyzed,'yymmdd hh24:mi:ss') last_anlzd DATAFIX.AEGFWSCEFOE_TEMP 10,000 071105 22:00:52 10,000 0 .000 ,nvl(dbta.num_rows,0)+nvl(dtm.inserts,0) GATEWAY.AEFSSTEFFFE 2,083 080212 16:03:36 2,08tot_rows 0 .000 -nvl(dtm.deletes,0) MM_AUDIT.ACCOUNSGSEGEGGEIT 2,083 071105 22:00:21 2,083 0 .000 ,nvl(dtm.inserts,0)+nvl(dtm.deletes,0)+nvl(dtm.updates,0) chngs MIDDLEOFFICE.ASGESGEPOTALLOCAT 123,944 080602 22:00:40 123,944 0 .000 ,(nvl(dtm.inserts,0)+nvl(dtm.deletes,0)+nvl(dtm.updates,0)) GATEWAY.ENBZHEERHWV 39,136 080522 22:06:39 44,922pct_c 6,156 .131 /greatest(nvl(dbta.num_rows,0),1) DATAFIX.RWERNGNONNGNVZBYNO 17,650 080425 22:00:04 17,650 0 .000 from dba_tables dbta DATAFIX.WEGEBTRUUUXTDWTTHH 32,707 071105 22:01:00 32,707 0 .000 left outer join dba_tab_modifications dtm DATAFIX.ACGERTIIJJYKYNJNIY 189 080131 22:00:03 189 0 .000 on dbta.owner = dtm.table_owner MM_AUDIT.KUKLYUTDJJ4YUNYJJ 313,230 080509 22:07:34 426,192 112,962 .251 and dbta.table_name = dtm.table_name DATAFIX.AERGERHGGRE_TEMP 10,000 071105 22:00:52 10,000 0 .000 and dtm.partition_name is null GATEWAY.AEFSSTEFFFE 2,083 080212 16:03:36 15,231 0 .000 where dbta.table_name like upper(nvl('&Tab_name','WHOOPS')) / clear colu Ora 600 Ltd 12/45 SYS.COL_USAGE$ • Every time a SQL statement is parsed, information about columns referenced in table joins and where predicates is stored in the internal table SYS.COL_USAGE% • This is what DBMS_STATS uses to help decide which of the indexed columns to gather stats on when method_opt “for all indexed columns” is used. • It might also play a part in deciding which columns to gather histograms on, as I have tested adding very skewed columns to a table and the automatic stats collection does not gather histograms and neither does a specific call to gather_stats with method_opt=“auto”. • It can also be useful to use, to help identify if an index is missing or even is likely to be used Ora 600 Ltd 13/45 OWNER COLUMN_NAME -- chk_col_usageTAB_NAME ------------------------------------------------------------------ this is a rip-off of Tim Gormans' script to look at the column usage info that,in EQUAL_PREDS EQI_JOINS NONEGI_JNS RANGE_PRDS LIKE_PRDS NULL_PRDS TS -9i,10g and 11 beta at least, is not--------revealed--------in a DB------------view. Gits ----------- --------------------------col owner form a22 wrap COMMHOME COMM_TRAD_PCTTRAD_H TREENODEID col tab_name form a30 wrap 2 0 0 0 0 0 02 JUN 2011 12:44:22 col column_name form a30 wrap col equal_preds COMM_TRAD_PIPREFUND form 9999,999 COMMHOME CC col eqi_joins form 9999,999 0 3 0 0 0 0 02 JUN 2011 10:59:13 col noneqi_jns form 9999,999 COMMHOME COMM_TRAD_PIPREFUND HOMEID col range_prds form 9999,999 col like_prds form 4,581 10 9999,9990 0 0 0 15 JUN 2011 20:38:44 col null_prds form 9999,999 COMMHOME COMM_TRAD_PIPREFUND ISLEAF select oo.name owner 163tab_name0 0 0 0 0 15 JUN 2011 20:38:44 , o.name COMMHOME COMM_TRAD_PIPREFUND TREENODEID , c.name column_name , u.equality_preds 177 169 equal_preds 0 0 0 0 15 JUN 2011 20:38:44 , u.equijoin_preds eqi_joins SYS TS$ FLAGS , u.nonequijoin_preds nonegi_jns 3,102 0 0 0 0 0 14 JUN 2011 23:33:37 , u.range_preds range_prds , u.like_preds like_prds SYS TS$ NAME , u.null_preds null_prds 2,708 1,954 5 0 392 0 15 JUN 2011 12:22:23 , u.timestamp ts SYS TS$ u ONLINE$ from sys.col_usage$ 3,553 o 0 0 0 0 0 15 JUN 2011 06:38:16 , sys.obj$ , sys.user$ oo SYS TS$ TS# , sys.col$ c 0 86 0 0 15 JUN 2011 18:08:32 where1,132 o.obj# =8,555 u.obj# GATEWAY TRADINGPERIODPROFILEDATA TRADINGCLOSE and oo.user# = o.owner# and c.obj# 0 = u.obj# 0 0 1 0 0 29 MAR 2011 05:23:45 and c.col# = u.intcol# GATEWAY TRADINGPERIODPROFILES INSTGROUPID and o.name like upper(nvl('&tab_name','%'))||'%' 46 237 0 0 0 0 12 JUN 2011 11:09:17 and oo.name like upper(nvl('&tab_own','%'))||'%' GATEWAY PROFILENAME order by 1,2,3 TRADINGPERIODPROFILES / 0 67 0 0 1 0 12 JUN 2011 00:53:36 clear colu GATEWAY TRADINGPERIODPROFILES SOURCEID 44 234 0 0 0 0 12 JUN 2011 11:09:17 14/45 Ora 600 Ltd Statistics Hierarchy There is more than one type of “stats” that Oracle can gather and which have different impacts and are best gathered in different ways. Gather “once” – How big your memory objects are Areas of memory, number of users, size of caches X$ sys-only “objects” FIXED OBJECT STATISTICS OBJECT STATISTICS Auto Gather DICTIONARY STATISTICS Gather regularly, probably via auto stats job Do not enhance or do one-offs Essentially “normal” stats for sys.obj$-type things Gather regularly, via auto job and enhancements Tables, Indexes, Columns What DBAs/Developers mean by “Stats” Increasing Impact Gather “once” – how fast the hardware is. Multi-Block read : Single-Block +Speed of your COU SYSTEM STATISTICS System Statistics • In effect, these stats are just the CPU speed and the relative speeds of Single-Block Reads (SBR) and Multi-Block Reads (MBR). • The actual speed of single- and multi- block reads are recorded, in milliseconds, but it is the ratio between them that counts. • If Multi-Block reads are found to be the same or faster than SingleBlock reads, Oracle 10 ignores the data collected, does not store it. • The CBO converts all IO and CPU cost into units of single-block reads. That is what the COST is in explain plan. It is also what you see in AWR. • Gathering System Statistics may: • push oracle towards or away from high-CPU actions like sorts. • Alter the likelihood of full table scans and fast full index scans as oracle better understands the cost of the multi-block actions. ORA600 Ltd 16/45 System Statistics • V10 and 11 come with a default set of system statistics. You can GATHER_SYSTEM_STATS with a fake workload or based on activity on your system over a period of time. • I advise the latter – but ensure your system has a representative workload. • You only need to gather the System Statistics “once” (but ensure you do so with an “average load”). • Re-gathering is only required if your storage changes (eg add more spindles), if there is a major system change or the server(s) you use change significantly in CPU utilisation • Gathering at day and night and storing/swapping system stats is often suggested – but seems to be a bit of an urban myth. • You may wish to gather system stats 4 or 5 times and DBMS_STATS.SET_SYSTEM_STATS to the average. • NB Not RAC aware – system stats gathered on one node apply to all ORA600 Ltd 17/45 Fixed Object Statistics • These are statistics on the in-memory “dynamic performance” objects, the x$ and similar tables (what V$ views sit on). • Need to gather “once” and only re-gather if something significant changes such as allocating much more memory to the instance or the number of user sessions greatly increasing. • Gathering Fixed Object stats will aid internal SQL, checking session details, looking at memory constructs. I have seen a small improvement in parse speed. Certain dictionary queries run faster. • Re-gather after upgrade etc. • If they have never been gathered the impact can be significant, I have yet to personally see a major change as a result of re-gathering (I just do so once a year on “just in case” principles). ORA600 Ltd 18/45 Dictionary Statistics • Statistics on the internal tables owned by SYS and other internal Oracle users. SYS.OBJ$, SYS.TAB%, SYS.TS$, those tables. • Are gathered as part of the default statistics gathering job. • In effect just like gathering schema statistics on the SYS, SYSTEM, OUTLN and other users. Support (and recommended {*} ) from V10. V9, keep with the RBO. • Can take several hours to gather on a database with tens of thousands of objects or more. • Can significantly aid parsing and other internal SQL, as well as DBA scripts running on the DBA views and also the underlying tables. ORA600 Ltd 19/45 Dictionary Statistics • Gather them regularly. Weekly to monthly. • If you use the default automatic statistics gathering job, it is collecting dictionary statistics for you and is fine. • If you disable the automatic statistics gathering for your schema stats either: • Leaving it running for ONLY Dictionary statistics: DBMS_PARAM.SET_PARAM(‘AUTOSTATS_TARGET’,’ORACLE’) • Organise regular dictionary stats gathering by your own methods. • Not gathering Dictionary Stats, especially on very large/complex database could lead to very poor dictionary/parse performance. • To be honest, with 10.1/10.2 at least, even gathering Dictionary Stats for systems with massive numbers of segments can fail to resolve some slow Dictionary performance ORA600 Ltd 20/45 That was the pre-amble. Getting the System, Fixed Object and Dictionary stats gathered gives you a solid base to tackle Object Statistics ORA600 Ltd 21/45 Why are Stats Key to Performance? • Used by the Cost Based Optimiser (CBO). • CBO examines the SQL statement and works out the various ways in which it could satisfy the query (up to about 2,000 plans under 10). • For each step the CBO works out the cost, which is expected IO plus CPU (if turned on) and the cardinality, the number of records that step will return. • The cardinality is passed back to the next step and can be a multiplier of that step’s cost. • The costs are added up and Oracle then picks the plan with the lowest overall cost(*) and runs that plan (*) This is a slight lie, but the principal is true Ora 600 Ltd 22/45 Why are Stats Key to Performance? • The CBO is very logical, it uses just the figures it is presented with and simple calculations to make it’s decision. No magic involved. • If those figures are wrong, ie the statistics are not representative then the costs calculated will be incorrect. • A small error can cascade up the code and cause a large difference to other steps and cause the plan to change. • With edge cases, a small difference often result in a different plan being chosen. • That different plan is often sub-optimal, sometimes seriously so, occasionally hundreds or thousands of times slower. • Cost/Cardinality being too low , often 1, is the most common cause of poor performance, due to prompting nested loop plans and incorrect driving tables Ora 600 Ltd 23/45 Automated Stats Gathering • If the automated job is working for you, leave it alone. • If you turned off the automated job and “wrote your own” under V10 or before and now are on 11 – consider going back to the automated job. It is faster and more accurate. • If you turned off the automated job and did not do anything about your Dictionary stats, that is bad. • Under V11 you can control %stale and defaults like method_opt at table level. Consider doing that. • If you decided to “roll your own” I would advise you leave the automated job running but just for Oracle’s objects: dbms_stats.set_global_prefs(autostats_target,’ORACLE’) ORA600 Ltd 24/45 Stats Gathering • Version 9, swap to DBMS_STATS and write your own • Version 10, use the automated job (at least for dictionary stats) write your own version/exceptions for your tables. • V11.1 – Test, do not trust me, but I would still say go auto. • V11.2 – Use the automated job and if you must intervene, use default sample size so you get one pass NDV. • V11 – look at rolling up stats for partitions, subpartitions – but read up on it extensively. You have to ensure you gather all partitions or sub-partitions. • With all versions of Oracle you will have exceptions, usually overnight batch or partitioned tables. If you are the DBA, this is part of your job. ORA600 Ltd 25/45 New Oracle 11 NDV • One of the most demanding parts of generating object statistics is gathering Number of Distinct Values • Oracle 11 introduced the single-pass NDV function. It scans the data once, uses much less memory, is faster and more accurate. • You have to use: ESTIMATE_PERCENT=DBMS_STATS.AUTO_SAMPLE_SIZE • You cannot use BLOCK sampling. Amit poddar via JL http://jonathanlewis.files.wordpress.com/2011/12/one-pass-distinct-samplingpresentation.pdf http://structureddata.org/2007/09/17/oracle-11g-enhancements-to-dbms_stats/ https://blogs.oracle.com/optimizer/entry/improvement_of_auto_sampling_statisti cs_gathering_feature_in_oracle_database_11g ORA600 Ltd 26/45 The Automated Job may Choke ORA600 Ltd 27/45 select substr(operation,1,30) operation ,to_char(start_time,'DD-MON-YYYY HH24:MI:SS.FF') START_tme ,to_char(END_TIME,'DD-MON-YYYY HH24:MI:SS.FF') end_tme from sys.WRI$_OPTSTAT_OPR order by start_time desc OPERATION -----------------------------gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_dictionary_stats gather_dictionary_stats gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) gather_database_stats(auto) START_TME -----------------------------02-JUN-2011 22:00:02.979206 31-MAY-2011 06:00:02.811976 30-MAY-2011 22:00:01.976379 29-MAY-2011 22:00:01.416256 28-MAY-2011 22:00:02.243542 27-MAY-2011 22:00:03.588237 26-MAY-2011 22:00:01.602425 24-MAY-2011 11:42:31.771667 24-MAY-2011 11:42:11.396340 24-MAY-2011 06:00:02.905945 23-MAY-2011 22:00:01.732964 22-MAY-2011 22:00:01.421518 21-MAY-2011 22:00:01.942455 20-MAY-2011 22:00:03.066981 19-MAY-2011 22:00:02.571718 17-MAY-2011 06:00:01.462810 16-MAY-2011 22:00:01.096761 Ora 600 Ltd END_TME --------------------02-JUN-2011 23:04:37 31-MAY-2011 06:56:21 30-MAY-2011 22:19:31 29-MAY-2011 23:36:14 29-MAY-2011 00:12:18 27-MAY-2011 23:14:24 26-MAY-2011 23:14:05 24-MAY-2011 11:42:35 24-MAY-2011 11:42:15 24-MAY-2011 06:20:38 23-MAY-2011 22:58:35 23-MAY-2011 06:00:05 22-MAY-2011 06:00:01 21-MAY-2011 06:00:01 19-MAY-2011 23:04:27 17-MAY-2011 08:02:34 16-MAY-2011 23:14:56 28/45 Fixing Choked Stats • Once the automated job chokes, it will continue to choke. Every night. This is because it tries the same thing each night. • The longer weekend run should sort things out – until it chokes. • Identify the table (Look for the gather statement interactively during the window, pull off the list of tables to gather options=list_stale, check for large objects with 10% difference...) • Do a manual gather with something like: block_sample=>true, estimate_percent=>0.1, degree=>8 method_opt=>for all columns size 1,cascade=> false, noinvalidate=>false, granualrity=>global • Once that is run you can afford to do a larger sample size and do the indexes. Do the PK first. • You probably need to lock the stats on the table and treat it as an exception. ORA600 Ltd 29/45 The Biggest “Wrong Stats” Issues The below are the worst “stats” causes of performance issues, in order, in my opinion based on experience 1. The stats say a segment is empty and it is not. 2. Your WHERE predicates are out of range for the known column values. 3. The stats say a segment holds than 10* less data than it does. The more orders of magnitude out, the worse. 4. Histograms. (there and not need or need and not there. Ouch) 5. The correlation between columns is not understood by the optimiser e.g. That values in tab1.x “line up” with those in tab2.y 6. Edge cases that experts get excited about but 99% of us never see Ora 600 Ltd 30/45 Stats Issues are a VLDB thing? • I can only go one what I have seen and, to a less turstworthy level (*ironic given the sources), what I have heard... • OLTP systems with a need for the fastest absolute response time to small data queries are NOT troubled by object stats. • Edge cases that balance on correlation or swapping to nested loop from hash or using Cartesian join are specific to OLTP and a set of requirements where stats gathering are, well, redundant. • Where pain occurs is when a plan that hashes several segments together {often including partition exclusion} swaps to either a nested loop or Cartesian merge join that is not suitable • When it comes down to it, the plan for large volumes of data is right for all volumes of data. If it does it in 30 seconds inefficiently, doing it in 33 second efficiently is spot-on good enough. ORA600 Ltd 31/45 Single Values Expected Outside of range 100 Oracle 10 with no Histograms 10,000 values Expect No Of values 0 100 200 300 400 300 400 300 400 300 400 100 Oracle 10 with Histograms 10,000 values Expect No Of values 0 100 200 100 Oracle 11 with no Histograms 10,000 values Expect No Of values 0 100 200 100 Oracle 11 with Histograms 10,000 values Expect No Of values 0 100 Or 200 100 10,000 values Expect No Of values 0 100 ORA600 Ltd 200 300 400 32/45 Range Values Expected Outside of range 100 Oracle 10 with no Histograms 10,000 values Expect No Of values 0 200 300 100 Oracle 10 with Histograms 10,000 values Expect No Of values 0 200 300 100 Oracle 11 with no Histograms 10,000 values Expect No Of values 0 200 300 100 Oracle 11 with Histograms 10,000 values Expect No Of values 0 200 ORA600 Ltd 300 33/45 Histograms and Data Ranges • Oracle 10 deals with column values being “out of range” by decreasing cardinality over that range • Eg if the low_value is 200 and the high_value is 300 and there are 1000 rows, that is 10 rows for 225. • For 350, it is 50% outside the range, so 10 rows is reduced by 50% to 5 rows. At value 400 it drops to 1 row. This is fine if you gather at 10%. • Histograms massively alter this “out of range” half-life. I have seen massive issues with dates. A table covering 5 years of data, with histograms on the date, can reduce a value only a week out of range to less then 1% of the average value. • This is a big issue on large tables that have stats gathered only occasionally (as not changed by a big percentage). ORA600 Ltd 34/45 Histograms and Partitions • This Out of Range issue is thrown into sharp relief with Partitions. • If the partitions are daily or weekly and have histograms on them, SQL statement selecting data for the latest hour can become “out of range” sooner than you can believe. • Spot this by the cardinality being 1 rather than several hundred or thousand. • Can happen even without histograms, especially with daily partitions • Solutions? Use dynamic sampling on latest daily or weekly partitions (your in-house code either does not collect or deletes such stats), insert half-day stats or gather very aggresively. ORA600 Ltd 35/45 Replacing the Automatic Stats Job The CBO is Complex. Stats are in effect a constantly evolving part of your code base. A simple approach will only work on a simple system. (And I really am Sorry!) ORA600 Ltd 36/45 Replacing the AUTO stats job • Don’t • Tweak the current job – make it run at different times, alter the %stale and defaults at table levels. • Locks the stats on the tables that give you issues and treat these as your exceptions. • If you MUST replace the Auto job it will hurt: • Initial estimate for “simple” replacement will be a week or two. • If you plan and estimate it, that will come out as four weeks. • It will take you 2 months. • You will emulate most of what the AUTO job does. • Your solution will probably need to look at segment size, DBA_TAB_MODIFICATIONS and have several control table that allow you to specify METHOD_OPT, SAMPLE SIZE and GRANULARITY at table level... ORA600 Ltd 37/45 Auto Stats Replacement OBJ_CTL OWNER TAB_NAME PART_NAME DFLT_STALE DFLT_SAMPLE DFLT_METHOD_OPT IDX_PCT Your Stats Job STATS_CTL DBA_TAB_MODS DBA_SEGMENTS LIST_STALE/EMPTY COPY RULES SAVE_STATS STATS_LOG BLOCK SAMPLE TAB THEN INDEX ORDER BY SIZE ASC ALL COLUMNS SIZE 1 PARALLEL ORA600 Ltd 38/45 Block or Row Sample • When you stats an ESTIMATE_PERCENT for a table gather statement, you can also state if it is block or row sample. It defaults to Row. • Row sample selects the percentage rows scattered across all Breaking of news! blocks. If you have eg 16k block size and over 100 rows per block, a 1%sample size will visit every block. There appears to be some issue with block sampling on • Block sample selects whole blocks, which greatly reduces the version 10.2 physical IO You can use the SAMPLE command in normal SQL • Block sample size gives low column cardinalities and is susceptible to select statements and that is what Oracle does to gather getting high-low values that are not close to the true edges. stats. However, the BLOCK SAMPLE seems to vary the • The under-sampling of columns depending on spread, but my actual number of blocks itvaries checks for a given sample tests show that 5% block sample size is about as good as 0.8% row size. sample size, but still 10 times faster. It is fine for 99% of cases. I will investigate when I have time. • Oracle V11 up – the new NDV and speed of stats pushes me back towards AUTO SAMPLE SIZE ORA600 Ltd 39/45 Write Something to Gather Stats on all Segments • You need to gather stats on each segment that needs stats. I strongly suggest any in-house code works segment-by-segment such that all tables, partitions and index segments are processed “as one” • You could use GATHER_SCHEMA_STATS and LIST the objects into an array and process. This gets object s Oracle would deem in need of stats: o STALE list those objects that have stats but have changed by 10% o EMPTY list those objects with no current stats o AUTO is supposed to list both but is buggy in 10.2.0.3 • Alternatively, run through all segments in the schemas you are interested in and used DBA_TAB_MODIFICATIONS directly. Slower (*) but much more control • I used the above on 10.1 but on current 10.2 system, the data dictionary is too slow. We decided to revert to GATHER_SCHEMA_STATS ORA600 Ltd 40/45 Do not write code to roll back stats. • Oracle keeps all stats changed for 31 day, by default. • You can alter this with DBMS_STATS.ALTER_STATS_HISTORY_RETENTION, check it with DBMS_STATS.GET_STATS_HISTORY_RETENTION (usualy 31). • If the stats history is causing you issues use PURGE_STATS to get rid of them but, be warned, once gone they are gone. But then, how often do you RESTORE stats? • Unless you REALLY want to be able to identify sets of stats, just use Oracle’s in-built feature where it stores previous stats for 31 days and you can recover them. • This hidden feature can create a LOT of data, especially if you have lots of partitions with lots of column stats. It goes into SYSTEM TS. http://mwidlake.wordpress.com/2009/08/03/why-is-my-system-tablespace-so-big/ ORA600 Ltd 41/45 Rolling Back Statistics • Most people are aware of the potential to have a user_statistics_table. This is a table you create that you can put stats into using EXPORT_XXXX_STATS and retrieve them with IMPORT_XXXX_STATS • You use the CREATE_STAT_TABLE table to create the table and give a STATID to sets of stats you wish to export and import. • One little Gotcha. The documentation is not clear, if you state a user statistics table in GATHER_XXXX_STATISTICS then they are NOT placed into the stats table, they are put in the dictionary and the OLD values are put in the stats table. • Rolling back stats works for system, fixed_object, database and object stats. I’ve tested it, it works – at least under 10.1 and 10.2. • Oracle 11 allows you to create Pending Stats which is very nice. It beats the manually version I developed for V10 in...ohh... 2005? ORA600 Ltd 42/45 Rolling Back • Gathering System ,Fixed Object and Dictionary statistics are “system wide” changes. Do you have a suitable system to test this on? • All have equivalent DBMS_STATS.RESTORE_XXXX_STATISTICS commands that, when I tested on 10.2.0.3, worked correctly (including blanking stats that were previously null). • You could save the stats being replaced in your own statistics table and recover from there. The only advantage is it is easier to interrogate stats you saved into your own stats table. • Deleting System Stats reinstigates the default values seen after install. • Deleting Fixed Object stats deletes the stats. • Deleting Dictionary stats is not a very good idea as it works. • I said you could restore Dictionary stats but, even though I tested it, I am not going to promise that all stats will be the same after you restore... ORA600 Ltd 43/45 Tables Cascade or Not? • If you gather statistics on a Table or Table Partition, the default is to CASCADE to relevant index segments. • The default will gather between 1000 and 2000 index blocks. I find this to be overkill. • By NOT cascading to index partitions but doing the indexes specifically and setting a sample size derived from the index size, you can use smaller samples sizes. • However, this is more code to write and test. It may be more pragmatic to just cascade, though each index segment may end up taking as long as the table segment to be gathered. • Consider global indexes and partitioned global indexes. ORA600 Ltd 44/45 DBMS_STATS Package • Many of us still refer to “analyze the table” but of course we all now mean “gather statistics with DBMS_STATS”. Don’t we . • Don’t use ANALYZE any more, especially not on production systems. • DBMS_STATS gathers better statistics, including histograms, and cascade down to partitions and sub-partitions as needed. • Can be run for specific segments (table, index, partition thereof etc), for a schema or for the database and can be set to only gather “stale” objects. • Can use Parallel to make up for the slower running, can set sample size by row and block (see more later) • In these slides, any procedure or function is in DBMS_STATS unless otherwise specified. ORA600 Ltd 45/45 Stability and Performance Dichotomy • To get the best performance, you want the stats to be as up-to-date and accurate as possible. • When the stats change, it is like having a miniture code Please note, the actual result of the data processing does release. The processing of the application can change – not change, the functionality is preserved, but the time after all, that is the idea. taken can change, the idea being it changes for the better • How many people here would allow a code release on their business critical systems at any time? • Most people are not actually concerned with good performance, they are concerned with poor performance. • Code can suddenly start running slowly “over night” when stats are gathered. Just one very bad statement can actually make the system unusable. Ora 600 Ltd 46/45 Why are Bad Stats worse than No Stats? • As an example, stats showing a table or partition is empty will cause the CBO to think it is a cost of 1 to scan and only one record will be found. Nested loops to access it and Cartesian Merge plans will occur. • More later, but stats saying there is no data later than a month ago will cause the CBO to again assume there is as little as one record to find. • If there are no stats, Oracle will use dynamic sampling or use defaults, which are usually better than bad stats • Spotting Bad Stats is not as easy as spotting missing Stats, especially as Oracle stores high/low values and histograms in internal formats. • Old stats (a specific type of bad stats) can cause a plan to flip to another plan without notice, with NO CHANGE. ORA600 Ltd 47/45 Intervention methods for stats • Stated low percentage stats gathering for large objects – use BLOCK SAMPLING and do tables and indexes specifically. • Set statistics manually or COPY_TABLE_STATS. The tricky part is the column stats and any histograms you have to have. • Delete and lock stats and allow Dynamic Sampling to occur. • Gather stats at lowest level (sub-partition or Partition) and allow them to be calculated at higher levels via Incremental stats. Made possible via synopses (but needs care to implement) • The overall aim is always the same. You do not need accurate stats, you need stats that are good enough to give execution plans that will work for large data volumes ORA600 Ltd 48/45 When to Gather • Most sites have stats gathering over night, even if they replace the auto stats gathering job. This may well not be the best time, • You may be better off collecting stats in the late evening or early morning. You can use PARALLEL to get the job done more quickly. • You are very unlikely to benefit from gathering all stats in one window. • If you are processing date into a table, gather the stats at the right time(s). This is probably after the load, or it could be several times in the process. • So long as only specific gathering is done, there is great benefit to be had gathering stats as your batch process proceeds. ORA600 Ltd 49/45 When to Gather-Batch Processing • I’m soooooo tired of this conversation and I have had it so many times... Batch processing means you need to think about stats • You have a table that is empty. You stuff it full of data. You use it to load data into your live database. Then you may or may not truncate it. Ask yourself, when is the volume of data significant and when do you gather stats. • If it is a global temporary table you may need to set some stats. • If I was to be given a pound for each time I had seen that the batch processing had no concept of stats gathering I would have £17.50. • So long as only specific gathering is done, there is great benefit to be had gathering stats as your batch process proceeds. ORA600 Ltd 50/45 Incremental Stats • I’m sorry but I ripped it out. There is nothing between “you can do it” and “here is how it works” that is not 1 min or 30 mins. • Do NOT attempt before V11, even though it is back-ported to 10.2.0.4 and .5. I’ve tried, it was hard. It was not nice. • You gather stats at the lowest level, sub-partition or partition at a reasonable level. These are summed up. Synopses are used to allow NDV calculations. Better than the crap I came up with.. • YOU HAVE TO BE RIGOROUS in ensuring all stats are gathered at the lowest levels and issues do not occur, but it works well if controlled. • No one seems to mention this, but, it all falls apart when you add new columns to a table. It won’t handle this as far as I have seen and those tables with stats that no longer update? Urrrrgghhhh. ORA600 Ltd 51/45 One Extreme - Dynamic Sampling Delete stats from a table and lock the table. • If there are no stats for a table, they are gathered from the table as it is now, thus avoiding issues with the table having recently changed. • You set the level of DYNAMIC SAMPLING at the instance level. In 10.2 it defaults to 2, gather stats on any segment lacking them, • At level 3, Guesses for filter predicates are checked and at level 4 correlation between columns are checked. These can greatly improve performance. • Only the data sampled can be considered and this is going to either be much less than that considered by a GATHER statement or else will take a long time to sample. • Levels above 4 increase the number of blocks assessed by the dynamic sample, up to 10 which is “every block”. Don’t do that. ORA600 Ltd 52/45 Dynamic Sampling • Dynamic sampling can be set at the database level (optimizer_dynamic_sampling) or in hints. • I would suggest setting the database level to 3 or 4 on a Datawarehouse, but I’ve not had much success getting Live sites to do this. • Dynamic sampling does extend parse times (sometimes to several seconds, potentially) so not suitable for sites with high SQL statement turnover (ie no use of binds). Which is a shame as binds cause other issues, with histograms and correlation! • Some people argue that, on DWs, delete all user-table (and index)stats, lock the tables and use dynamic sampling alone. • I repeat, Not suitable for OLTP-like SQL activity. ORA600 Ltd 53/45 Other Extreme - Freezing Stats • DBMS_STATS.LOCK_TABLE_STATS and LOCK_SCHEMA_STATS allow you to lock the stats. Can’t lock at partition or index. • The automated stats collection will leave those segments (and their dependents) alone unless you use the ‘force=true’ parameter. • Individual gather/set/delete/import stats statements on a locked table will cause an error. • Locking populated stats will help preserve an execution plan, which gives stability but prevents improvements. However, you can’t stop time. • If you delete the stats first and lock them, they stay empty, allowing dynamic sampling to prevail. • If you lock the stats, people or processes gathering stats THAT SHOULD NOT BE will fail. Can re-enable via the force parameter Ora 600 Ltd 54/45 Locking Stats • If you lock the stats on a table then Oracle will not collect them anymore. • If you lock a table with empty stats, the CBO will dynamically sample the table when the SQL statment is parsed. This is fine for long running SQL like on Data Warehouses and utterly unacceptable for OLTP systems where you need the answer in 100ms. • If you have gathered stats on an empty table and lock the stats you are in a world of pain as the CBO will think there are no rows and base it’s plan on that. • If you gather stats when you know that they will be good, and then lock them, then your execution plans will probably be good. • If you have a complex situation but know what stats are needed, you can SET those stats and lock the table. No more stats will be gathered. Everything will be fine until the world moves on. ORA600 Ltd 55/45 Histograms • Histograms and bind variables do not mix well on Oracle 10 due to bind peeking. Oracle 11 is supposed to fix this. • In essence, if the first bind values seen by the parse are not typical (or match a low-cardinality plan) the plan chosen can perform very poorly for larger returned data sets. • These bad plans can get stuck in the SGA. Eg takes 11 minutes to run and kicked off every 10 minutes. You can’t get the code out of the SGA. • Histograms increase the time taken to gather stats significantly. Oracle 10.1 and 10.2 massively over-gather histograms. • If you write your own code you can stop histograms being gathered. • But Histograms are really good for some code. • If only there was a “parse” hint ORA600 Ltd 56/45 Further Information • PL/SQL Packages and Types Reference, DBMS_STATS • Blogs - Jonathan Lewis (generally), Doug Burns (recent series on partitions and stats), Christian antognini, follow links to others • My Blog, I intend to do some more posts on stats gathering. • Email me and ask, I’m happy to answer general questions if I can. • Your system. ORA600 Ltd 57/45 Table Sample Size • Generally speaking, the larger the table the smaller the sample size you need for “good enough” statistics. • I usually decide on a percentage sample size derived from the number of blocks in the table, aiming for 1000 to 10,000 blocks. • SIZE_AUTO samples 0.01% then 0.1% (or similar) and sees if the stats change significantly, then increase the percentage size until the stats are stable or a compute is quicker. • SIZE_AUTO sounds clever but works out, in practice, to usually be inefficient. Just does not cope with lots of large segments. If you think about it, it almost guarantees gathering at a samples size larger than you need before stopping. • May want to gather the table only with no CASCADE to indexes as Oracle over-samples indexes with the cascade option (I hardly every use CASCADE in replacements for the auto job) ORA600 Ltd 58/45 I over-ran, didn’t I? And I kept it to 45 slides. Oh Well, next SIG... ORA600 Ltd 59/45 Template Picture Slide ORA600 Ltd 60/45