Oracle Optimizer Bootcamp 10 Optimizer tips you can't do without Maria Colgan & Jonathan Lewis
PART 2
2 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Program Agenda
. Using the right tools . Finding the right sample size . Tell the optimizer everything . Functions friends or foe . Most useful hints to know
3 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Tell the Optimizer everything
. The Optimizer makes assumptions in certain case – Each additional where clause predicates reduces the number of rows – Each additional group by column will increase number of rows returned – Applying a function to column will alter the NDV of the column . Sometimes you know more about your data than basic statistics show – Best way to get a good plan is to tell the Optimizer everything – Otherwise it assumes, making an ass out of u and me
4 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Tell the optimizer everything Correlated column example
SELECT * FROM vehicles WHERE model = ‘530xi’ AND color = 'RED’;
MAKE MODEL COLOR Year BMW 530xi RED 2013
Cardinality = #ROWS * 1 * 1 => 12 * 1 * 1 = 1 NDV c1 NDV c2 4 3
5 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Tell the optimizer everything Correlated column example
SELECT * FROM vehicles WHERE model = ‘530xi’ AND make = ‘BMW’; MAKE MODEL COLOR Year BMW 530xi RED 2013 BMW 530xi BLACK 2011 BMW 530xi BLUE 2012 Cardinality #ROWS * 1 * 1 => 12 * 1 * 1 = 1 NDV c1 NDV c2 4 3
6 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Create extended statistics on column group DBMS_STATS.CREATE_EXTENDED_STATS
New Column with system generated name
7 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Tell the optimizer everything Correlated column example with extended statistics
SELECT * FROM vehicles WHERE model = ‘530xi’ AND make = ‘BMW’; MAKE MODEL COLOR Year BMW 530xi RED 2013 BMW 530xi BLACK 2011 BMW 530xi BLUE 2012
Cardinality calculated using column group statistics
8 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Tell the Optimizer everything Automatic column group detection
. Use SEED_COL_USAGE to have Oracle monitor workload . Can monitor STS or live system . Recommends what column groups are needed based on workload
9 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Bad Defaults (a)
create table t1 as select decode( mod(rownum - 1,1000), -- every 1000th row 0,to_date('31-Dec-4000'), -- is a 'null' date to_date('01-Jan-2010') + trunc((rownum-1)/100) ) date_closed from large_data_source where rownum <= 1827 * 100 -- 5 years in days * 100 ;
10 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Bad Defaults (b)
select * from t1 where date_closed -- 36,500 rows between to_date('01-Jan-2012','dd-mon-yyyy') and to_date('31-Dec-2012','dd-mon-yyyy'); With simple statistics. TABLE ACCESS (FULL) OF 'T1' (Cost=46 Card=291 Bytes=2328)
With 11 column histogram (two per year and one for the garbage) TABLE ACCESS (FULL) OF 'T1' (Cost=46 Card=36320 Bytes=290560)
With nulls and simple statistics. TABLE ACCESS (FULL) OF 'T1' (Cost=46 Card=36583 Bytes=256081)
11 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Graphical Interpretation
Data for 2012 The real data
Oracle's first impression
Impression with histogram
12 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Bad Data Types (a) create table t1 as select d1, -- date to_number(to_char(d1,'yyyymmdd')) n1, -- numeric to_char(d1,'yyyymmdd') v1 -- char from ( select to_date('31-Dec-2009') + rownum d1 from all_objects where rownum <= 1827 -- 5 years, daily );
13 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Bad Data Types (b)
select * from t1 where d1 -- 7 rows between to_date('30-Dec-2012','dd-mon-yyyy') and to_date('05-Jan-2013','dd-mon-yyyy'); On the date type. TABLE ACCESS (FULL) OF 'T1' (Cost=3 Card=8 Bytes=184) N1 between 20121230 and 20030105 TABLE ACCESS (FULL) OF 'T1' (Cost=3 Card=397 Bytes=9131) V1 between ' 20121230' and '20030105' TABLE ACCESS (FULL) OF 'T1' (Cost=3 Card=457 Bytes=10511) 10g+ gets Card=397 - everything looks like numbers)
14 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Histogram effects:
. N1 between 20121230 and 20130105 – pre-histogram TABLE ACCESS (FULL) OF 'T1' (Cost=3 Card=397 Bytes=9131) – post-histogram TABLE ACCESS (FULL) OF 'T1' (Cost=3 Card=32 Bytes=736)
. V1 between ' 20121230' and '20130105‘ ‒ pre-histogram TABLE ACCESS (FULL) OF 'T1' (Cost=3 Card=457 Bytes=10511) ‒ post-histogram TABLE ACCESS (FULL) OF 'T1' (Cost=3 Card=30 Bytes=690)
15 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Graphical Interpretation The real (char/number) data
Oracle's first impression
Impression with histogram
16 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Program Agenda
. Using the right tools . Finding the right sample size . Tell the optimizer everything . Functions friends or foe . Most useful hints to know
17 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Functions friends or foe? Expected index range scan but got fast full index scan
. Query – How many packages of bounce did we sell? SELECT count(*)
FROM sales2
WHERE to_char(prod_id)=‘139’;
. Sales 2 has a b-tree index on the prod_id column
18 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Functions friends or foe?
Cardinality estimate is in the right ballpark so not a problem with statistics Why is an equality predicate being evaluated as a filter and not an access
predicate? Could it have something to do with the TO_CHAR function
19 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Functions friends or foe?
. INTERNAL_FUNCTION indicates Oracle needs to modify predicate – In this case a data type conversion occurred . Predicate is TO_CHAR(prod_id) . Optimizer has no idea how function effects values in prod_id column . Optimizer can’t determine which rows will be accessed now
20 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Functions friends or foe?
. What data type is the prod_id column ?
. But literal value is a character string ‘139’
Better to apply inverse function on other side of predicate
21 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Functions friends or foe? Solution - Use inverse function on other side of predicate
Query rewrite SELECT count(*) FROM sales2 WHERE prod_id=to_number(‘139’);
22 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Functions friends or foe? Using inverse function on other side of predicate
. Keep the following in mind when deciding where to place the function – Try to place functions on top of constants (literals, binds) rather than on columns – Avoid functions on index columns or partition keys as it prevents index use or partition pruning – For function-based index to be considered, use that exact function as specified in index – If multiple predicates involve the same columns, write predicates such that they share common expressions For example, WHERE f(a) = b WHERE a = inv_f(b) This will allow transitive Should be predicate c=inv_f(b) to be AND a = c rewritten as AND a = c added by the optimizer
23 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Virtual Columns (a)
create table t1 as Select cast(rownum as number(8,0)) id1, cast(rownum as number(8,0)) id2 from all_objects where rownum <= 10000 ; alter table t1 add m2 generated always as ( mod(id2,3)) virtual ; execute dbms_stats.gather_table_stats(user,'t1');
24 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Virtual Columns (b)
set autotrace traceonly explain select * from t1 where mod(id1,3) = 0; . |* 1 | TABLE ACCESS FULL| T1 | 100 | 1100 | 4 |
Predicate Information (identified by operation id): 1 - filter(MOD("ID1",3)=0)
select * from t1 where mod(id1,3) != 0; . |* 1 | TABLE ACCESS FULL| T1 | 500 | 5500 | 4 |
Predicate Information (identified by operation id): 1 - filter(MOD("ID1",3)<>0)
25 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Virtual Columns (c)
set autotrace traceonly explain select * from t1 where mod(id2,3) = 0; . |* 1 | TABLE ACCESS FULL| T1 | 3333 | 36663 | 4 |
Predicate Information (identified by operation id): 1 - filter("T1"."M2"=0)
select * from t1 where mod(id2,3) != 0; . |* 1 | TABLE ACCESS FULL| T1 | 6667 | 73337 | 4 |
Predicate Information (identified by operation id): 1 - filter("T1"."M2"<>0)
26 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Program Agenda
. Using the right tools . Finding the right sample size . Tell the optimizer everything . Functions friends or foe . Most useful hints to know
27 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Most useful hints to know Understanding Optimizer hints
. Hints allow you to influence the Optimizer when it has to choose between several possibilities . A hint is a directive that will be followed when applicable . Can influence everything from the Optimizer mode used to each operation in the execution . The hint mechanism is not exclusively used by the Optimizer . Some of the most useful hint influence SQL execution
28 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Most useful hints to know GATHER_PLAN_STATISTICS hint
. GATHER_PLAN_STATISTICS triggers execution time statistics to be preserved . Records actual number of rows seen for each operation (step) in plan . Execution statistis displayed in plan when format parameter of DMBS_XPLAN set to ALLSTATS LAST – Means display all execution statistics for last execution of this cursor
29 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. GATHER_PLAN_STATISTICS hint
. SELECT * FROM table ( . DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST'));
. Compare estimated rows returned for each operation to actual rows
30 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. GATHER_PLAN_STATISTICS Hint
SELECT * FROM table ( DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST')); Note: a lot of the data is zero in the A-rows column because we only show last executed cursor which is the QC. Need to use ALLSTATS ALL to see info on all parallel server cursors
31 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. GATHER_PLAN_STATISTICS Hint
SELECT * FROM table ( DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS ALL'));
32 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Alternatively using MONITOR hint
33 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Most helpful hints to know OPT_PARAM hint
. Allows value for init.ora Optimizer parameters to be changed for a specific query . Useful way to prevent setting non-default parameter value system-wide . Only the following Optimizer influencing init.ora parameters can be set: . OPTIMIZER_DYNAMIC_SAMPLING . STAR_TRANSFORMATION_ENABLED . OPTIMIZER_INDEX_CACHING . PARALLEL_DEGREE_POLICY . OPTIMIZER_INDEX_COST_ADJ . PARALLEL_DEGREE_LIMIT . OPTIMIZER_USE_PENDING_STATISTICS . Optimizer related underscore parameters
34 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. OPT_PARAM hint Example
35 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. OPT_PARAM hint Example
36 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Most useful hints to know OPTIMIZER_FEATURES_ENABLE hint
. OPTIMIZER_FEATURES_ENABLE parameter allows you to switch between optimizer versions . Setting it to previous database version reverts the Optimizer to that version – Disables any functionality that was not present in that version . Easy way to work around unexpected behavior in a new release . Hint allows you to revert the Optimizer for just a single statement
37 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Precision matters (a)
select /*+ parallel(pt1,2) */ {list of columns} from pt1 where pt1.n1 = 5 The optimizer DID obey the hint and pt1.n2 = 10 and pt1.pt_group in (0,10) ; . |Id|Operation |Name |Cost |Pstart| Pstop| | 0|SELECT STATEMENT | | 48| | | | 1| PARTITION LIST INLIST | | 48|KEY(I)|KEY(I)| |*2| TABLE ACCESS BY LOCAL INDEX ROWID|PT1 | 48|KEY(I)|KEY(I)| |*3| INDEX RANGE SCAN |PT1_I1| 3|KEY(I)|KEY(I)|
38 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Precision matters (b)
... NESTED LOOP TABLE ACCESS (FULL) OF T7 TABLE ACCESS BY INDEX ROWID T8 INDEX RANGE SCAN T8_IND_SECOND -- “wrong” index ... select /*+ index(t8 t8_ind_first) */ -- hint the “right” one
... HASH JOIN -- wrong method TABLE ACCESS (FULL) OF T7 TABLE ACCESS BY INDEX ROWID T8 INDEX FULL SCAN T8_IND_FIRST -- “right” index ...
39 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. How much don't we know ? select /*+ leading(t4 t1 t2 t3) full(t4) use_hash(t1) full(t1) use_hash(t2) full(t2) use_hash(t3) full(t3) */ ... From t4, t1, t2, t3 Where t1.id = t4.id1 and t2.id = t4.id2 and t3.id = t4.id3;
40 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. How much don't we know ? N – 1 simultaneous build (hash) tables HASH JOIN TABLE ACCESS (FULL) OF TABLE_3 HASH JOIN TABLE ACCESS (FULL) OF TABLE_2 HASH JOIN TABLE ACCESS (FULL) OF TABLE_1 TABLE ACCESS (FULL) OF TABLE_4
Maximum two simultaneous build (hash) tables HASH JOIN HASH JOIN HASH JOIN TABLE ACCESS (FULL) OF TABLE_4 TABLE ACCESS (FULL) OF TABLE_1 TABLE ACCESS (FULL) OF TABLE_2 TABLE ACCESS (FULL) OF TABLE_3
41 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. Summary
. Forgive the Optimizer – it’s not out to get you – Its knowledge is limited to the information you provide it . A complete representative set of statistics gets the best plans – Determine or have Oracle determine what extended statistics are needed . Be mindful of when you capture a representative set of statistics – Don’t be afraid to adjust maintenance window or include statistics in ETL . Optimizer hints should only be used with extreme caution – To guarantee the same plan every time use SQL Plan Baselines . Enjoy the challenge!
42 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. More Information . White papers – Optimizer with Oracle Database 12c – SQL Plan Management with Oracle Database 12c – Understanding Optimizer Statistics with Oracle Database 12c . Blogs – http://jonathanlewis.wordpress.com/all-postings/ – http://blogs.oracle.com/optimizer . Oracle.com – http://www.oracle.com/technetwork/database/focus-areas/bi- datawarehousing/dbbi-tech-info-optmztn-092214.html
43 Copyright © 2013, Oracle and/or its affiliates. All rights reserved. 44 Copyright © 2013, Oracle and/or its affiliates. All rights reserved.