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 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 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 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.