+ All Categories
Home > Documents > A few things about the Optimizer Thomas Kyte

A few things about the Optimizer Thomas Kyte

Date post: 25-Dec-2015
Category:
Upload: amberly-casey
View: 213 times
Download: 0 times
Share this document with a friend
83
A few things about the Optimizer Thomas Kyte http://asktom.oracle.com/
Transcript
Page 1: A few things about the Optimizer Thomas Kyte

A few things about the Optimizer

Thomas Kytehttp://asktom.oracle.com/

Page 2: A few things about the Optimizer Thomas Kyte

Understanding Access Paths for the RBO

Using the RBO, the optimizer chooses an execution plan based on the access paths available and the ranks of these access paths. Oracle's ranking of the access paths is heuristic. If there is more than one way to execute a SQL statement, then the RBO always uses the operation with the lower rank. Usually, operations of lower rank execute faster than those associated with constructs of higher rank.

The list shows access paths and their ranking:

• RBO Path 9: Single-Column Indexes

• RBO Path 10: Bounded Range Search on Indexed Columns

• RBO Path 11: Unbounded Range Search on Indexed Columns

• RBO Path 12: Sort Merge Join

• RBO Path 13: MAX or MIN of Indexed Column

• RBO Path 14: ORDER BY on Indexed Column

• RBO Path 15: Full Table Scan

• RBO Path 1: Single Row by Rowid

• RBO Path 2: Single Row by Cluster Join

• RBO Path 3: Single Row by Hash Cluster Key with Unique or Primary Key

• RBO Path 4: Single Row by Unique or Primary Key

• RBO Path 5: Clustered Join

• RBO Path 6: Hash Cluster Key

• RBO Path 7: Indexed Cluster Key

• RBO Path 8: Composite Index

Page 3: A few things about the Optimizer Thomas Kyte

<Insert Picture Here>

Datatypes

Page 4: A few things about the Optimizer Thomas Kyte

4

Using the Wrong Datatype

• Datatypes are constraints• Optimizer uses constraints• Database uses constraints (31-feb-2010)• If you use the wrong data type you will– Lose data integrity– Confuse the optimizer– Spend a lot of CPU converting things so you can use builtin

features

Page 5: A few things about the Optimizer Thomas Kyte

5

Wrong Datatypes

ops$tkyte%ORA11GR2> create table t 2 as 3 select object_name, object_type, owner, 4 to_date( '01-jan-2007', 'dd-mon-yyyy' ) + rownum DT, 5 to_char( 6 to_date( '01-jan-2007', 'dd-mon-yyyy' ) + rownum, 7 'YYYYMMDD' 8 ) STR, 9 to_number( 10 to_char( 11 to_date( '01-jan-2007', 'dd-mon-yyyy' ) + rownum, 12 'YYYYMMDD' ) 13 ) NUM 14 from all_objects a 15 order by dbms_random.random 16 /

Table created.

Page 6: A few things about the Optimizer Thomas Kyte

6

Wrong Datatypes

ops$tkyte%ORA11GR2> create index dt_idx on t(dt);

Index created.

ops$tkyte%ORA11GR2> create index str_idx on t(str);

Index created.

ops$tkyte%ORA11GR2> create index num_idx on t(num);

Index created.

Page 7: A few things about the Optimizer Thomas Kyte

7

Wrong Datatypes

ops$tkyte%ORA11GR2> select count(object_type) from t 2 where dt = trunc(sysdate);COUNT(OBJECT_TYPE)------------------ 1

ops$tkyte%ORA11GR2> select count(object_type) from t 2 where str = to_char(trunc(sysdate),'YYYYMMDD');COUNT(OBJECT_TYPE)------------------ 1

ops$tkyte%ORA11GR2> select count(object_type) from t 2 where num = to_number(to_char(trunc(sysdate),'YYYYMMDD'));COUNT(OBJECT_TYPE)------------------ 1

“seed” dbms_stats if necessary…

Page 8: A few things about the Optimizer Thomas Kyte

8

Wrong Datatypes

ops$tkyte%ORA11GR2> exec dbms_stats.gather_table_stats(user,'T');

PL/SQL procedure successfully completed.

ops$tkyte%ORA11GR2> select column_name, histogram 2 from user_tab_columns 3 where table_name = 'T';

COLUMN_NAME HISTOGRAM------------------------------ ---------------OBJECT_NAME NONEOBJECT_TYPE NONEOWNER NONEDT NONESTR NONENUM NONE

6 rows selected.

Page 9: A few things about the Optimizer Thomas Kyte

9

Wrong Datatypes

ops$tkyte%ORA11GR2> select count(object_type) from t 2 where str between '20131231' and '20140101';

COUNT(OBJECT_TYPE)------------------ 2

ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor);---------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 192 (100)| || 1 | SORT AGGREGATE | | 1 | 18 | | ||* 2 | TABLE ACCESS FULL| T | 327 | 5886 | 192 (1)| 00:00:03 |---------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - filter(("STR"<='20140101' AND "STR">='20131231'))

Page 10: A few things about the Optimizer Thomas Kyte

10

Wrong Datatypes

ops$tkyte%ORA11GR2> select count(object_type) from t 2 where num between 20131231 and 20140101;

COUNT(OBJECT_TYPE)------------------ 2

ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor);---------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 192 (100)| || 1 | SORT AGGREGATE | | 1 | 15 | | ||* 2 | TABLE ACCESS FULL| T | 327 | 4905 | 192 (1)| 00:00:03 |---------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - filter(("NUM"<=20140101 AND "NUM">=20131231))

Page 11: A few things about the Optimizer Thomas Kyte

11

Wrong Datatypes

ops$tkyte%ORA11GR2> select count(object_type) from t 2 where dt between to_date( '31-dec-2013', 'dd-mon-yyyy' ) 3 and to_date( '01-jan-2014', 'dd-mon-yyyy' );

COUNT(OBJECT_TYPE)------------------ 2

ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor);--------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Tim--------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 6 (100)|| 1 | SORT AGGREGATE | | 1 | 17 | || 2 | TABLE ACCESS BY INDEX ROWID| T | 3 | 51 | 6 (0)| 00:|* 3 | INDEX RANGE SCAN | DT_IDX | 3 | | 2 (0)| 00:--------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

3 - access("DT">=TO_DATE(' 2013-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "DT"<=TO_DATE(' 2014-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'

Page 12: A few things about the Optimizer Thomas Kyte

12

Wrong Datatypes

ops$tkyte%ORA11GR2> exec dbms_stats.gather_table_stats(user,'T', method_opt=>'for all indexed columns');

PL/SQL procedure successfully completed.

ops$tkyte%ORA11GR2> pause

ops$tkyte%ORA11GR2>ops$tkyte%ORA11GR2> select column_name, histogram 2 from user_tab_columns 3 where table_name = 'T';

COLUMN_NAME HISTOGRAM------------------------------ ---------------OBJECT_NAME NONEOBJECT_TYPE NONEOWNER NONEDT HEIGHT BALANCEDSTR HEIGHT BALANCEDNUM HEIGHT BALANCED

6 rows selected.

Page 13: A few things about the Optimizer Thomas Kyte

13

Wrong Datatypes

ops$tkyte%ORA11GR2> select count(object_type) from t 2 where str between '20131231' and '20140101';

COUNT(OBJECT_TYPE)------------------ 2

ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor);---------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 192 (100)| || 1 | SORT AGGREGATE | | 1 | 18 | | ||* 2 | TABLE ACCESS FULL| T | 327 | 5886 | 192 (1)| 00:00:03 |---------------------------------------------------------------------------

Predicate Information (identified by operation id):--------------------------------------------------- 2 - filter(("STR"<='20140101' AND "STR">='20131231'))

Page 14: A few things about the Optimizer Thomas Kyte

14

Wrong Datatypes

ops$tkyte%ORA11GR2> select count(object_type) from t 2 where dt between to_date( '31-dec-2013', 'dd-mon-yyyy' ) 3 and to_date( '01-jan-2014', 'dd-mon-yyyy' );

COUNT(OBJECT_TYPE)------------------ 2

ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor);--------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Tim--------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 6 (100)|| 1 | SORT AGGREGATE | | 1 | 17 | || 2 | TABLE ACCESS BY INDEX ROWID| T | 3 | 51 | 6 (0)| 00:|* 3 | INDEX RANGE SCAN | DT_IDX | 3 | | 2 (0)| 00:--------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

3 - access("DT">=TO_DATE(' 2013-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "DT"<=TO_DATE(' 2014-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'

Page 15: A few things about the Optimizer Thomas Kyte

<Insert Picture Here>

Data Patterns Affect How Things Are Done

Page 16: A few things about the Optimizer Thomas Kyte

16

Knowledge of your data is a mandatory prerequisite to

understanding what is happening and why it is happening

Page 17: A few things about the Optimizer Thomas Kyte

Clustering Factor

ops$tkyte%ORA11GR2> create table organized 2 as 3 select x.* 4 from (select * from stage order by object_name) x 5 /

ops$tkyte%ORA11GR2> create table disorganized 2 as 3 select x.* 4 from (select * from stage order by dbms_random.random) x 5 /

Page 18: A few things about the Optimizer Thomas Kyte

Clustering Factor

ops$tkyte%ORA11GR2> create index organized_idx on organized(object_name);

Index created.

ops$tkyte%ORA11GR2> create index disorganized_idx on disorganized(object_name);

Index created.

Page 19: A few things about the Optimizer Thomas Kyte

Clustering Factorops$tkyte%ORA11GR2> begin 2 dbms_stats.gather_table_stats 3 ( user, 'ORGANIZED', 4 estimate_percent => 100, 5 method_opt=>'for all indexed columns size 254' 6 ); 7 dbms_stats.gather_table_stats 8 ( user, 'DISORGANIZED', 9 estimate_percent => 100, 10 method_opt=>'for all indexed columns size 254' 11 ); 12 end; 13 /

Page 20: A few things about the Optimizer Thomas Kyte

Clustering Factorops$tkyte%ORA11GR2> select table_name, blocks, num_rows, 0.05*num_rows, 0.10*num_rows from user_tables 2 where table_name like '%ORGANIZED' order by 1;

TABLE_NAME BLOCKS NUM_ROWS 0.05*NUM_ROWS 0.10*NUM_ROWS------------------------------ ---------- ---------- ------------- -------------DISORGANIZED 1062 72774 3638.7 7277.4ORGANIZED 1062 72774 3638.7 7277.4

ops$tkyte%ORA11GR2> select table_name, index_name, clustering_factor from user_indexes 2 where table_name like '%ORGANIZED' order by 1;

TABLE_NAME INDEX_NAME CLUSTERING_FACTOR------------------------------ ------------------------------ -----------------DISORGANIZED DISORGANIZED_IDX 72727ORGANIZED ORGANIZED_IDX 1036

Page 21: A few things about the Optimizer Thomas Kyte

Clustering Factor

ops$tkyte%ORA11GR2> select /*+ index( organized organized_idx) */ 2 count(subobject_name) 3 from organized;COUNT(SUBOBJECT_NAME)--------------------- 542

ops$tkyte%ORA11GR2> select /*+ index( disorganized disorganized_idx) */ 2 count(subobject_name) 3 from disorganized;COUNT(SUBOBJECT_NAME)--------------------- 542

Page 22: A few things about the Optimizer Thomas Kyte

Clustering Factorselect /*+ index( organized organized_idx) */ count(subobject_name) from organized

call count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 1 0.00 0.00 0 0 0 0Fetch 2 0.45 0.45 1036 1398 0 1------- ------ -------- ---------- ---------- ---------- ---------- ----------total 4 0.45 0.46 1036 1398 0 1

Row Source Operation---------------------------------------------------SORT AGGREGATE (cr=1398 pr=1036 pw=0 time=456653 us) TABLE ACCESS BY INDEX ROWID ORGANIZED (cr=1398 pr=1036 pw=0 time=376835 us cost=1400… INDEX FULL SCAN ORGANIZED_IDX (cr=362 pr=0 pw=0 time=98362 us cost=363 …

1,398-362 = 1,036 - the clustering factor…

Page 23: A few things about the Optimizer Thomas Kyte

Clustering Factorselect /*+ index( disorganized disorganized_idx) */ count(subobject_name) from disorganized call count cpu elapsed disk query current rows------- ------ -------- ---------- ---------- ---------- ---------- ----------Parse 1 0.00 0.00 0 0 0 0Execute 1 0.00 0.00 0 0 0 0Fetch 2 0.83 0.83 1036 73089 0 1------- ------ -------- ---------- ---------- ---------- ---------- ----------total 4 0.83 0.83 1036 73089 0 1

Row Source Operation---------------------------------------------------SORT AGGREGATE (cr=73089 pr=1036 pw=0 time=835554 us) TABLE ACCESS BY INDEX ROWID DISORGANIZED (cr=73089 pr=1036 pw=0 time=750651 us … INDEX FULL SCAN DISORGANIZED_IDX (cr=362 pr=0 pw=0 time=96421 us cost=363 …

73,089-362 = 72,727 - the clustering factor…

Page 24: A few things about the Optimizer Thomas Kyte

Clustering Factor

ops$tkyte%ORA11GR2> select * from organized where object_name like 'F%';

Execution Plan----------------------------------------------------------Plan hash value: 1925627673

-------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CP-------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 149 | 14453 | 6 (| 1 | TABLE ACCESS BY INDEX ROWID| ORGANIZED | 149 | 14453 | 6 (|* 2 | INDEX RANGE SCAN | ORGANIZED_IDX | 149 | | 3 (-------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("OBJECT_NAME" LIKE 'F%') filter("OBJECT_NAME" LIKE 'F%')

Page 25: A few things about the Optimizer Thomas Kyte

Clustering Factor

ops$tkyte%ORA11GR2> select * from disorganized where object_name like 'F%';

Execution Plan----------------------------------------------------------Plan hash value: 3767053355

-------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (-------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 149 | 14453 | 152| 1 | TABLE ACCESS BY INDEX ROWID| DISORGANIZED | 149 | 14453 | 152|* 2 | INDEX RANGE SCAN | DISORGANIZED_IDX | 149 | | 3-------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("OBJECT_NAME" LIKE 'F%') filter("OBJECT_NAME" LIKE 'F%')

Page 26: A few things about the Optimizer Thomas Kyte

Clustering Factor

ops$tkyte%ORA11GR2> select * from organized where object_name like 'A%';

Execution Plan----------------------------------------------------------Plan hash value: 1925627673

-------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CP-------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1824 | 172K| 38 (| 1 | TABLE ACCESS BY INDEX ROWID| ORGANIZED | 1824 | 172K| 38 (|* 2 | INDEX RANGE SCAN | ORGANIZED_IDX | 1824 | | 12 (-------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("OBJECT_NAME" LIKE 'A%') filter("OBJECT_NAME" LIKE 'A%')

Page 27: A few things about the Optimizer Thomas Kyte

Clustering Factor

ops$tkyte%ORA11GR2> select * from disorganized where object_name like 'A%';

Execution Plan----------------------------------------------------------Plan hash value: 2727546897

-------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time-------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1824 | 172K| 290 (1)| 00:00:0|* 1 | TABLE ACCESS FULL| DISORGANIZED | 1824 | 172K| 290 (1)| 00:00:0-------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

1 - filter("OBJECT_NAME" LIKE 'A%')

Page 28: A few things about the Optimizer Thomas Kyte

Not understanding WHY something worked

Page 29: A few things about the Optimizer Thomas Kyte

For Example:

• Query runs great in test• Same query runs great in production• Until it doesn’t• Call Support – suggest: gather stats, they seem stale• You do that, query runs great• Until it doesn’t• Gather Stats again, query runs great• Until it doesn’t

• Did statistics “fix” it?

Page 30: A few things about the Optimizer Thomas Kyte

+peeked_binds

ops$tkyte%ORA11GR2> create table t 2 as 3 select 99 id, a.* 4 from all_objects a 5 where rownum <= 20000;

Table created. ops$tkyte%ORA11GR2> update t 2 set id = 1 3 where rownum = 1;1 row updated.

ops$tkyte%ORA11GR2> create index t_idx on t(id);Index created.

Page 31: A few things about the Optimizer Thomas Kyte

+peeked_binds

ops$tkyte%ORA11GR2> begin 2 dbms_stats.gather_table_stats 3 ( user, 'T', 4 method_opt=>'for all indexed columns size 254', 5 estimate_percent => 100, 6 cascade=>TRUE ); 7 end; 8 /

PL/SQL procedure successfully completed.

Page 32: A few things about the Optimizer Thomas Kyte

+peeked_binds

ops$tkyte%ORA11GR2> variable n numberops$tkyte%ORA11GR2> exec :n := 99;PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> select count(object_type) 2 from t 3 where id = :n;

COUNT(OBJECT_TYPE)------------------ 19999

Page 33: A few things about the Optimizer Thomas Kyte

+peeked_binds

ops$tkyte%ORA11GR2> exec :n := 1;

PL/SQL procedure successfully completed.

ops$tkyte%ORA11GR2> select count(object_type) 2 from t 3 where id = :n;

COUNT(OBJECT_TYPE)------------------ 1

Page 34: A few things about the Optimizer Thomas Kyte

+peeked_binds

ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor(format=>'+peeked_binds'));

---------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 82 (100)| || 1 | SORT AGGREGATE | | 1 | 14 | | ||* 2 | TABLE ACCESS FULL| T | 19999 | 273K| 82 (0)| 00:00:01 |---------------------------------------------------------------------------

Peeked Binds (identified by position):-------------------------------------- 1 - :N (NUMBER): 99

Predicate Information (identified by operation id):--------------------------------------------------- 2 - filter("ID"=:N)

Page 35: A few things about the Optimizer Thomas Kyte

+peeked_binds

ops$tkyte%ORA11GR2> begin 2 dbms_stats.gather_table_stats 3 ( user, 'T', 4 method_opt=>'for all indexed columns size 254', 5 estimate_percent => 100, 6 cascade=>TRUE, NO_INVALIDATE=>FALSE ); 7 end; 8 /

PL/SQL procedure successfully completed.

Page 36: A few things about the Optimizer Thomas Kyte

+peeked_binds

ops$tkyte%ORA11GR2> select count(object_type) 2 from t 3 where id = :n;

COUNT(OBJECT_TYPE)------------------ 1

ops$tkyte%ORA11GR2> ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor(format=>'+peeked_binds'));--------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time--------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 2 (100)|| 1 | SORT AGGREGATE | | 1 | 14 | || 2 | TABLE ACCESS BY INDEX ROWID| T | 1 | 14 | 2 (0)| 00:0|* 3 | INDEX RANGE SCAN | T_IDX | 1 | | 1 (0)| 00:0--------------------------------------------------------------------------------Peeked Binds (identified by position):-------------------------------------- 1 - :N (NUMBER): 1

Page 37: A few things about the Optimizer Thomas Kyte

Understand WHY it “worked”…

This case has nothing to do with statistics and everything to do with

bind variable peeking…

Or cardinality feedback

Or adaptive cursor sharing

Or …

Page 38: A few things about the Optimizer Thomas Kyte

Sometimes the explanation just doesn’t sound right..

Page 39: A few things about the Optimizer Thomas Kyte

Explain Plan “lies”

• Explain plan should hardly ever be used…• You have to be careful when using autotrace and

related tools• Never use “explain=u/p” with tkprof• Avoid dbms_xplan.display, use display_cursor

Page 40: A few things about the Optimizer Thomas Kyte

Explain plan lies…

ops$tkyte%ORA11GR2> create table t 2 as 3 select 99 id, to_char(object_id) str_id, a.* 4 from all_objects a 5 where rownum <= 20000;Table created.

ops$tkyte%ORA11GR2> update t 2 set id = 1 3 where rownum = 1;1 row updated.

ops$tkyte%ORA11GR2> create index t_idx on t(id);Index created.

ops$tkyte%ORA11GR2> create index t_idx2 on t(str_id);Index created.

Page 41: A few things about the Optimizer Thomas Kyte

Explain plan lies…

ops$tkyte%ORA11GR2> begin 2 dbms_stats.gather_table_stats 3 ( user, 'T', 4 method_opt=>'for all indexed columns size 254', 5 estimate_percent => 100, 6 cascade=>TRUE ); 7 end; 8 /

PL/SQL procedure successfully completed.

Page 42: A few things about the Optimizer Thomas Kyte

Explain plan lies…

Need a volunteer

Page 43: A few things about the Optimizer Thomas Kyte

Explain plan lies…

Need a volunteer

select count(*) from t where id = :n;

What cardinality would you estimate and why?

Page 44: A few things about the Optimizer Thomas Kyte

Explain plan lies…

ops$tkyte%ORA11GR2> variable n numberops$tkyte%ORA11GR2> exec :n := 99;PL/SQL procedure successfully completed.

ops$tkyte%ORA11GR2> set autotrace traceonly explainops$tkyte%ORA11GR2> select count(*) from t where id = :n;-------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 3 | 12 (0)| 00:00:01 || 1 | SORT AGGREGATE | | 1 | 3 | | ||* 2 | INDEX FAST FULL SCAN| T_IDX | 10000 | 30000 | 12 (0)| 00:00:01 |-------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - filter("ID"=TO_NUMBER(:N)) <<= a clue right here

Page 45: A few things about the Optimizer Thomas Kyte

Explain plan lies…

ops$tkyte%ORA11GR2> select count(*) from t where id = 1;

Execution Plan----------------------------------------------------------Plan hash value: 293504097

---------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 3 | 1 (0)| 00:00:01 || 1 | SORT AGGREGATE | | 1 | 3 | | ||* 2 | INDEX RANGE SCAN| T_IDX | 1 | 3 | 1 (0)| 00:00:01 |---------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("ID"=1)

Page 46: A few things about the Optimizer Thomas Kyte

Explain plan lies…

ops$tkyte%ORA11GR2> select count(*) from t where id = 99;

Execution Plan----------------------------------------------------------Plan hash value: 1058879072

-------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 3 | 12 (0)| 00:00:01 || 1 | SORT AGGREGATE | | 1 | 3 | | ||* 2 | INDEX FAST FULL SCAN| T_IDX | 19999 | 59997 | 12 (0)| 00:00:01 |-------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - filter("ID"=99)

Page 47: A few things about the Optimizer Thomas Kyte

Explain plan lies…

ops$tkyte%ORA11GR2> set autotrace traceonly explainops$tkyte%ORA11GR2> select object_id from t where str_id = :n;

--------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time--------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 19 | 2 (0)| 00:0| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 19 | 2 (0)| 00:0|* 2 | INDEX RANGE SCAN | T_IDX2 | 1 | | 1 (0)| 00:0--------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("STR_ID"=:N) <<== interesting…

Page 48: A few things about the Optimizer Thomas Kyte

Explain plan lies…

ops$tkyte%ORA11GR2> select object_id from t where str_id = :n;

OBJECT_ID---------- 99

ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor);--------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 86 (100)| ||* 1 | TABLE ACCESS FULL| T | 1 | 19 | 86 (0)| 00:00:02 |--------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

1 - filter(TO_NUMBER("STR_ID")=:N) <<= string has to convert..

Page 49: A few things about the Optimizer Thomas Kyte

Explain plan lies…

1 - filter(TO_NUMBER("STR_ID")=:N) <<= string has to convert..

STR_ID------0000000.00+0-0

1,0001.000

Page 50: A few things about the Optimizer Thomas Kyte

Parallel, how did that happen

Page 51: A few things about the Optimizer Thomas Kyte

Unplanned Parallel

• Everything is running normal• Reorganize (you know, to make things faster) over

the weekend• Monday rolls around and…

Page 52: A few things about the Optimizer Thomas Kyte

Unplanned Parallel

ops$tkyte%ORA11GR2> create table t 2 as 3 select * 4 from all_objects;Table created.

ops$tkyte%ORA11GR2> create index t_idx on t(object_id);Index created.

ops$tkyte%ORA11GR2> exec dbms_stats.gather_table_stats( user, 'T' );PL/SQL procedure successfully completed.

Page 53: A few things about the Optimizer Thomas Kyte

Unplanned Parallel

ops$tkyte%ORA11GR2> select sum(object_id) 2 from t t1 3 where object_id > 5000;

SUM(OBJECT_ID)-------------- 2805618150

ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor);-------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 47 (100)| || 1 | SORT AGGREGATE | | 1 | 5 | | ||* 2 | INDEX FAST FULL SCAN| T_IDX | 70864 | 346K| 47 (3)| 00:00:01 |-------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - filter("OBJECT_ID">5000)

Page 54: A few things about the Optimizer Thomas Kyte

Unplanned Parallel

ops$tkyte%ORA11GR2> alter index t_idx rebuild parallel 4;

Index altered.

Page 55: A few things about the Optimizer Thomas Kyte

Unplanned Parallel

ops$tkyte%ORA11GR2> select sum(object_id) 2 from t t2 3 where object_id > 5000;

SUM(OBJECT_ID)-------------- 2805618150

ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor);--------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time--------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 47 (100)|| 1 | SORT AGGREGATE | | 1 | 5 | || 2 | PX COORDINATOR | | | | || 3 | PX SEND QC (RANDOM) | :TQ10000 | 1 | 5 | || 4 | SORT AGGREGATE | | 1 | 5 | || 5 | PX BLOCK ITERATOR | | 70864 | 346K| 47 (3)| 00:0|* 6 | INDEX FAST FULL SCAN| T_IDX | 70864 | 346K| 47 (3)| 00:0--------------------------------------------------------------------------------Predicate Information (identified by operation id):--------------------------------------------------- 6 - access(:Z>=:Z AND :Z<=:Z) filter("OBJECT_ID">5000)

Page 56: A few things about the Optimizer Thomas Kyte

Unplanned Parallel

ops$tkyte%ORA11GR2> select 'T', table_name, degree 2 from user_tables 3 where table_name = 'T' 4 union all 5 select 'I', index_name, degree 6 from user_indexes 7 where table_name = 'T';

' TABLE_NAME DEGREE- ------------------------------ ------------T T 1I T_IDX 4

Page 57: A few things about the Optimizer Thomas Kyte

The optimizer isn’t pushy enough

Page 58: A few things about the Optimizer Thomas Kyte

Pushing

• Create a view• Query view using a predicate• Discover that the view is materialized AND THEN the

predicate is applied• Run query with predicate – predicate is evaluated as

the query is done, resulting in far far superior performance

• BUT…

Page 59: A few things about the Optimizer Thomas Kyte

Pushing

ops$tkyte%ORA11GR2> create table emp as select * from scott.emp;Table created.

ops$tkyte%ORA11GR2> create index job_idx on emp(job);Index created.

ops$tkyte%ORA11GR2> exec dbms_stats.set_table_stats ( user, 'EMP', numrows => 1000000 );PL/SQL procedure successfully completed.

Page 60: A few things about the Optimizer Thomas Kyte

Pushing

ops$tkyte%ORA11GR2> create or replace view v 2 as 3 select ename, sal, job, 4 sum(sal) over (partition by job) sal_by_job, 5 sum(sal) over (partition by deptno) sal_by_deptno 6 from emp 7 /View created.

Page 61: A few things about the Optimizer Thomas Kyte

Pushing

ops$tkyte%ORA11GR2> select * 2 from v 3 where job = 'CLERK' 4 order by ename 5 /

ENAME SAL JOB SAL_BY_JOB SAL_BY_DEPTNO---------- ---------- --------- ---------- -------------ADAMS 1100 CLERK 4150 10875JAMES 950 CLERK 4150 9400MILLER 1300 CLERK 4150 8750SMITH 800 CLERK 4150 10875

--------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |--------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | | 33026 (100)| || 1 | SORT ORDER BY | | 1000K| 49M| 65M| 33026 (1)| 00:06:37 ||* 2 | VIEW | V | 1000K| 49M| | 20141 (1)| 00:04:02 || 3 | WINDOW SORT | | 1000K| 37M| 49M| 20141 (1)| 00:04:02 || 4 | WINDOW SORT | | 1000K| 37M| 49M| 20141 (1)| 00:04:02 || 5 | TABLE ACCESS FULL| EMP | 1000K| 37M| | 41 (30)| 00:00:01 |--------------------------------------------------------------------------------------Predicate Information (identified by operation id): 2 - filter("JOB"='CLERK')

Page 62: A few things about the Optimizer Thomas Kyte

Pushing

ops$tkyte%ORA11GR2> select ename, sal, job, 2 sum(sal) over (partition by job) sal_by_job, 3 sum(sal) over (partition by deptno) sal_by_deptno 4 from emp 5 where job = 'CLERK' order by ename;

Page 63: A few things about the Optimizer Thomas Kyte

Pushing

ops$tkyte%ORA11GR2> select ename, sal, job, 2 sum(sal) over (partition by job) sal_by_job, 3 sum(sal) over (partition by deptno) sal_by_deptno 4 from emp 5 where job = 'CLERK' order by ename;

ENAME SAL JOB SAL_BY_JOB SAL_BY_DEPTNO---------- ---------- --------- ---------- -------------ADAMS 1100 CLERK 4150 1900JAMES 950 CLERK 4150 950MILLER 1300 CLERK 4150 1300SMITH 800 CLERK 4150 1900

-----------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| T-----------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | | 207 (100)| | 1 | SORT ORDER BY | | 10000 | 380K| 520K| 207 (2)| 0| 2 | WINDOW SORT | | 10000 | 380K| 520K| 207 (2)| 0| 3 | WINDOW BUFFER | | 10000 | 380K| | 207 (2)| 0| 4 | TABLE ACCESS BY INDEX ROWID| EMP | 10000 | 380K| | 2 (0)| 0|* 5 | INDEX RANGE SCAN | JOB_IDX | 14 | | | 1 (0)| 0-----------------------------------------------------------------------------------------Predicate Information (identified by operation id):5 - access("JOB"='CLERK')

Page 64: A few things about the Optimizer Thomas Kyte

Pushing

ops$tkyte%ORA11GR2> select ename, sal, sal_by_job 2 from v 3 where job = 'CLERK' 4 order by ename 5 /

ENAME SAL SAL_BY_JOB---------- ---------- ----------ADAMS 1100 4150JAMES 950 4150MILLER 1300 4150SMITH 800 4150

----------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| ----------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | | 97 (100)| | 1 | SORT ORDER BY | | 10000 | 341K| 480K| 97 (2)| | 2 | VIEW | V | 10000 | 341K| | 2 (0)| | 3 | WINDOW BUFFER | | 10000 | 253K| | 2 (0)| | 4 | TABLE ACCESS BY INDEX ROWID| EMP | 10000 | 253K| | 2 (0)| |* 5 | INDEX RANGE SCAN | JOB_IDX | 14 | | | 1 (0)| ----------------------------------------------------------------------------------------Predicate Information (identified by operation id):5 - access("JOB"='CLERK')

Page 65: A few things about the Optimizer Thomas Kyte

Why do we gather statistics?

Page 66: A few things about the Optimizer Thomas Kyte

“Cardinality”

Page 67: A few things about the Optimizer Thomas Kyte

“Wrong Cardinality => Wrong Plan”

Page 68: A few things about the Optimizer Thomas Kyte

“Wrong Plan => Wrong Cardinality”

Page 69: A few things about the Optimizer Thomas Kyte

Wrong Plan => Wrong Cardinality

ops$tkyte%ORA11GR2> create table t

2 as select decode( mod(rownum,2), 0, 'N', 'Y' ) flag1,

3 decode( mod(rownum,2), 0, 'Y', 'N' ) flag2, a.*

4 from all_objects a

5 /

Table created.

ops$tkyte%ORA11GR2> create index t_idx on t(flag1,flag2);

Index created.

ops$tkyte%ORA11GR2> begin

2 dbms_stats.gather_table_stats

3 ( user, 'T',

4 method_opt=>'for all indexed columns size 254' );

5 end;

6 /

PL/SQL procedure successfully completed.

Page 70: A few things about the Optimizer Thomas Kyte

Wrong Plan => Wrong Cardinality

ops$tkyte%ORA11GR2> select 'select * from t', num_rows

2 from user_tables where table_name = 'T'

3 union all

4 select 'select * from t where flag1 = "N"', num_rows/2

5 from user_tables where table_name = 'T'

6 union all

7 select 'select * from t where flag2 = "N"', num_rows/2

8 from user_tables where table_name = 'T'

9 union all

10 select 'select * from t where flag1 = "N" and flag2 = "N"', num_rows/2/2

11 from user_tables where table_name = 'T';

'SELECT*FROMT' NUM_ROWS

------------------------------------------------- ----------

select * from t 72726

select * from t where flag1 = "N" 36363

select * from t where flag2 = "N" 36363

select * from t where flag1 = "N" and flag2 = "N" 18181.5

Page 71: A few things about the Optimizer Thomas Kyte

Wrong Plan => Wrong Cardinality

ops$tkyte%ORA11GR2> set autotrace traceonly explain

ops$tkyte%ORA11GR2> select * from t where flag1='N';

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 36499 | 3635K| 301 (1)| 00:00:04 |

|* 1 | TABLE ACCESS FULL| T | 36499 | 3635K| 301 (1)| 00:00:04 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("FLAG1"='N')

Page 72: A few things about the Optimizer Thomas Kyte

Wrong Plan => Wrong Cardinality

ops$tkyte%ORA11GR2> select * from t where flag2='N';

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 36227 | 3608K| 301 (1)| 00:00:04 |

|* 1 | TABLE ACCESS FULL| T | 36227 | 3608K| 301 (1)| 00:00:04 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("FLAG2"='N')

Page 73: A few things about the Optimizer Thomas Kyte

Wrong Plan => Wrong Cardinality

ops$tkyte%ORA11GR2> select * from t where flag1='N' and flag2='N';

--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 18181 | 1810K| 301 (1)| 00:00:04 |

|* 1 | TABLE ACCESS FULL| T | 18181 | 1810K| 301 (1)| 00:00:04 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("FLAG2"='N' AND "FLAG1"='N')

Page 74: A few things about the Optimizer Thomas Kyte

Wrong Plan => Wrong Cardinality

ops$tkyte%ORA11GR2> select /*+ gather_plan_statistics */ *

2 from t where flag1='N' and flag2='N';

no rows selected

Page 75: A few things about the Optimizer Thomas Kyte

Wrong Plan => Wrong Cardinality

ops$tkyte%ORA11GR2> select * from

table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

PLAN_TABLE_OUTPUT

------------------------------------------------------------------------------------

| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |

------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.02 | 1080 |

|* 1 | TABLE ACCESS FULL| T | 1 | 18181 | 0 |00:00:00.02 | 1080 |

------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter(("FLAG2"='N' AND "FLAG1"='N'))

19 rows selected.

Page 76: A few things about the Optimizer Thomas Kyte

Wrong Plan => Wrong Cardinality

ops$tkyte%ORA11GR2> select /*+ dynamic_sampling(t 3) */ * from t

where flag1='N' and flag2='N';

-------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 6 | 612 | 2 (0)| 00:00:01 |

| 1 | TABLE ACCESS BY INDEX ROWID| T | 6 | 612 | 2 (0)| 00:00:01 |

|* 2 | INDEX RANGE SCAN | T_IDX | 6 | | 1 (0)| 00:00:01 |

-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("FLAG1"='N' AND "FLAG2"='N')

Note

-----

- dynamic sampling used for this statement (level=2)

Page 77: A few things about the Optimizer Thomas Kyte

Wrong Plan => Wrong Cardinality

SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE

NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false')

NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */

NVL(SUM(C1),:"SYS_B_00"), NVL(SUM(C2),:"SYS_B_01"), NVL(SUM(C3),:"SYS_B_02")

FROM

(SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("T") FULL("T")

NO_PARALLEL_INDEX("T") */

:"SYS_B_03" AS C1,

CASE WHEN "T"."FLAG1"= :"SYS_B_04" AND "T"."FLAG2"=:"SYS_B_05"

THEN :"SYS_B_06"

ELSE :"SYS_B_07"

END AS C2,

CASE WHEN "T"."FLAG2"=:"SYS_B_08" AND "T"."FLAG1"=:"SYS_B_09“

THEN :"SYS_B_10"

ELSE :"SYS_B_11"

END AS C3

FROM "OPS$TKYTE"."T"

SAMPLE BLOCK (:"SYS_B_12" , :"SYS_B_13") SEED (:"SYS_B_14") "T") SAMPLESUB

Page 78: A few things about the Optimizer Thomas Kyte

X

• X• X• X• X• X

Page 79: A few things about the Optimizer Thomas Kyte

Programming to fail…

Page 80: A few things about the Optimizer Thomas Kyte

Programming to fail…

• Too smart for their own good• Parse count• Parse count (failures)

• Quick stories about parsing…

Page 81: A few things about the Optimizer Thomas Kyte

Programming to fail…

Begin

execute immediate

‘begin internal_pkg.some_code; end;’;

Exception

when others then null;

End;

Page 82: A few things about the Optimizer Thomas Kyte

Programming to fail…

Sandeep - my math was wrong, I said 40% of your hard parses were failed parses.  In looking at the numbers again:

Statistic                                     Total     per Second     per Trans-------------------------------- ------------------ -------------- -------------parse count (failures)                      389,176          109.0           3.0parse count (hard)                          607,096          170.1           4.7parse count (total)                       6,775,397        1,898.0          52.3

It would be correct to say that 64% (yes, 64%!!!!!!!!!!!!!) of your parses are *FAILED* parsed.  The parse count hard included failed and successful parses - therefore, it is 389k/607k*100 to get the right percentage.

2 out of 3 SQL statements FAIL PARSING.  That is sick

Page 83: A few things about the Optimizer Thomas Kyte

Recommended