Presentation is loading. Please wait.

Presentation is loading. Please wait.

A few things about the Optimizer Thomas Kyte

Similar presentations


Presentation on theme: "A few things about the Optimizer Thomas Kyte"— Presentation transcript:

1 A few things about the Optimizer Thomas Kyte http://asktom.oracle.com/

2 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

3 Datatypes

4 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

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

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

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

8 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 NONE OBJECT_TYPE NONE OWNER NONE DT NONE STR NONE NUM NONE 6 rows selected.

9 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" ='20131231'))

10 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" =20131231))

11 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'

12 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 NONE OBJECT_TYPE NONE OWNER NONE DT HEIGHT BALANCED STR HEIGHT BALANCED NUM HEIGHT BALANCED 6 rows selected.

13 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" ='20131231'))

14 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'

15 Data Patterns Affect How Things Are Done

16 16 Knowledge of your data is a mandatory prerequisite to understanding what is happening and why it is happening

17 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 /

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

19 Clustering Factor ops$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 /

20 Clustering Factor ops$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.4 ORGANIZED 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 72727 ORGANIZED ORGANIZED_IDX 1036

21 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

22 Clustering Factor select /*+ 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 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 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…

23 Clustering Factor select /*+ 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 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 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…

24 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%')

25 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%')

26 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%')

27 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%')

28 Not understanding WHY something worked

29 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?

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

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

32 +peeked_binds ops$tkyte%ORA11GR2> variable n number ops$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

33 +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

34 +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)

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

36 +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

37 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 …

38 Sometimes the explanation just doesn’t sound right..

39 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

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

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

42 Explain plan lies… Need a volunteer

43 Explain plan lies… Need a volunteer select count(*) from t where id = :n; What cardinality would you estimate and why?

44 Explain plan lies… ops$tkyte%ORA11GR2> variable n number ops$tkyte%ORA11GR2> exec :n := 99; PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> set autotrace traceonly explain ops$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

45 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)

46 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)

47 Explain plan lies… ops$tkyte%ORA11GR2> set autotrace traceonly explain ops$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…

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

49 Explain plan lies… 1 - filter(TO_NUMBER("STR_ID")=:N) <<= string has to convert.. STR_ID ------ 0 00 000 0.00 +0 -0 1,000 1.000

50 Parallel, how did that happen

51 Unplanned Parallel Everything is running normal Reorganize (you know, to make things faster) over the weekend Monday rolls around and…

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

53 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)

54 Unplanned Parallel ops$tkyte%ORA11GR2> alter index t_idx rebuild parallel 4; Index altered.

55 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)

56 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 1 I T_IDX 4

57 The optimizer isn’t pushy enough

58 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…

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

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

61 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 10875 JAMES 950 CLERK 4150 9400 MILLER 1300 CLERK 4150 8750 SMITH 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')

62 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;

63 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 1900 JAMES 950 CLERK 4150 950 MILLER 1300 CLERK 4150 1300 SMITH 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')

64 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 4150 JAMES 950 4150 MILLER 1300 4150 SMITH 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')

65 Why do we gather statistics?

66 “Cardinality”

67 “Wrong Cardinality => Wrong Plan”

68 “Wrong Plan => Wrong Cardinality”

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

70 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

71 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')

72 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')

73 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')

74 Wrong Plan => Wrong Cardinality ops$tkyte%ORA11GR2> select /*+ gather_plan_statistics */ * 2 from t where flag1='N' and flag2='N'; no rows selected

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

76 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)

77 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

78 X X

79 Programming to fail…

80 Too smart for their own good Parse count Parse count (failures) Quick stories about parsing…

81 Programming to fail… Begin execute immediate ‘begin internal_pkg.some_code; end;’; Exception when others then null; End;

82 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.0 parse count (hard) 607,096 170.1 4.7 parse 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

83


Download ppt "A few things about the Optimizer Thomas Kyte"

Similar presentations


Ads by Google