0% found this document useful (0 votes)
81 views

Oracle Database 10g SQL Optimization

One Nice Book and it is not mine. Find somewhere in net

Uploaded by

Larry Solomon
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
81 views

Oracle Database 10g SQL Optimization

One Nice Book and it is not mine. Find somewhere in net

Uploaded by

Larry Solomon
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 30

Oracle 10g Optimization Everywhere

Jonathan Lewis

Agenda
Who am I Areas of optimisation Past, Present and Future Q and A

Jonathan Lewis 2003-2004

Most slides have a foot-note. This is a brief summary of the comments that I should have made whilst displaying the slide, and is there for later reference.

Oracle 10 Evolution 2

Who am I ?
Independent Consultant. 19+ years in IT 16+ using Oracle Strategy, Design, Review Briefings, Seminars Trouble-shooting www.jlcomp.demon.co.uk
Jonathan Lewis 2003-2004 Oracle 10 Evolution 3

What is "Optimisation" ?
What do we want ?
Better performance for less cash

Better application code


done by the dba / developer

Better tools
let the dba/developer do a better job, faster

Better kernel code


Jonathan Lewis 2003-2004

When you think of optimisation, it's not just about ways to rewrite the SQL to make it go faster - Oracle keeps inventing new strategies, and new tools.

Oracle 10 Evolution 4

Case Study - Unnesting


Subqueries can become inline views Subqueries can become anti or semi-joins The optimizer may do it for you You may have to do it by hand Sometimes it is the wrong thing to do Sometimes there are better options anyway
Jonathan Lewis 2003-2004

As an indication of how things keep changing - and how we have to keep reviewing code on upgrades - we look at subquery unnesting.

Oracle 10 Evolution 5

Correlated Subquery (1)


select outer.* from emp outer where outer.sal > ( select /*+ unnest */ avg(inner.sal) from emp inner where inner.dept_no = outer.dept_no );

Jonathan Lewis 2003-2004

If you did not include the hint (which is not needed in Oracle 9) a query like this could be slow and expensive in Oracle 8.

Oracle 10 Evolution 6

Correlated Subquery (2)


Default execution path in 8.1.7 (has to be forced in 9i and 10g) FILTER TABLE ACCESS (FULL) OF EMP (Cost=34 Card=1000) SORT (AGGREGATE) TABLE ACCESS (FULL) OF EMP (Cost=34 Card=1000) The costs change dramatically with version - 10g gets it right. Oracle 8 : 34 Oracle 9 : 34,034 Oracle 10 : 238 (34 + 6 * 34)
num_distinct for dept_no in outer query
Jonathan Lewis 2003-2004

The execution plan suggests (incorrectly) that Oracle is doing a full tablescan and sort of the subqueried emp table for each row of the driving emp table.

Oracle 10 Evolution 7

Correlated Subq - SQL fix 1


The developer's solution in 8i
select from outer.* (select

dept_no, avg(sal) av_sal from emp group by dept_no ) inner, emp outer where outer.dept_no = inner.dept_no and outer.sal > inner.av_sal;
But the introduction of in-line views gave you an option for rewriting it to go faster (most of the time). See Gaja Vaidyanatha Performance Tuning 101.

Jonathan Lewis 2003-2004

Oracle 10 Evolution 8

Correlated Subq - plan


The execution path for the re-written SQL statement

SELECT STATEMENT Optimizer=CHOOSE (Cost=121 Card=1000) HASH JOIN (Cost=121 Card=1000) VIEW (Cost=86 Card=6) SORT (GROUP BY) (Cost=86 Card=6) TABLE ACCESS (FULL) OF EMP (Cost=34 Card=20000) TABLE ACCESS (FULL) OF EMP (Cost=34 Card=20000)

Jonathan Lewis 2003-2004

The plan shows that we have explicitly created a 'holding' view of the data, and then done a hash join from this temporary set to the main table.

Oracle 10 Evolution 9

Correlated Subq - Kernel Fix


Oracle Corp's solution in 9i and 10g The new plan for the original query
SELECT STATEMENT Optimizer=CHOOSE (Cost=73 Card=1000) HASH JOIN (Cost=73 Card=1000) VIEW OF VW_SQ_1 (Cost=50 Card=6) SORT (GROUP BY) (Cost=50 Card=6) TABLE ACCESS (FULL) OF EMP (Cost=22 Card=20000) TABLE ACCESS (FULL) OF EMP (Cost=22 Card=20000)
Not always needed e.g. already unique But just as the in-line view solution became popular, Oracle Corp. made it redundant. In Oracle 9 (or with the unnest hint) you get this execution path.

Jonathan Lewis 2003-2004

Oracle 10 Evolution 10

Correlated Subq - Problems


Check init.ora / spfile parameters in 9i _unnest_subquery = TRUE (was false) enables unnesting of correlated subqueries _unnest_notexists_sq = SINGLE (9i only) unnest NOT EXISTS subquery with one or more tables if possible
Oracle 9i unnests MOST subqueries without costing them Oracle 10g (usually) works out the cost of unnesting

Jonathan Lewis 2003-2004

Unnesting subqueries is often the best thing to do, but it isn't always the best thing to do. Oracle 10g checks to see if it is a good idea - Oracle 9i may not.

Oracle 10 Evolution 11

Correlated Subq - SQL option


select dept_no, emp_no, sal from ( select dept_no, emp_no, sal, avg(sal) over( partition by dept_no ) av_sal from emp ) where sal > av_sal;
Jonathan Lewis 2003-2004

You may do better than unnesting anyway. When you unnest you still scan the emp table twice. If you switch to analytic functions, you scan it once.

Oracle 10 Evolution 12

System Statistics (1)


dbms_stats.gather_system_stats('start') dbms_stats.gather_system_stats('stop')
SNAME SYSSTATS_MAIN SYSSTATS_MAIN SYSSTATS_MAIN SYSSTATS_MAIN SYSSTATS_MAIN SYSSTATS_MAIN PNAME CPUSPEED SREADTIM MREADTIM MBRC MAXTHR SLAVETHR PVAL1 559 1.299 10.204 4 13938448 3244736

-- (2.8GHz)

-- PX choke -- PX choke

Jonathan Lewis 2003-2004

One of the major features of Oracle 9 that should be included as part of the standard migration is the CPU-based costing feature. It is mandatory in 10g

Oracle 10 Evolution 13

System Statistics (2)


Cost = ( #SRds * sreadtim + #MRds * mreadtim + #CPUCycles / cpuspeed ) / sreadtim So cost is the elapsed time measured in units of single block reads.
Jonathan Lewis 2003-2004

This formula for cost appears in the 9.2 manuals. Effectively it says that cost really is supposed to be a prediction of elapsed time.

Oracle 10 Evolution 14

System Statistics (3)


Tablescan cost = (High Water Mark / MBRC statistic) * (mreadtim / sreadtim)+ a CPU component

Using multiple block sizes ?


Doubling the block size halves the HWM which doubles the impact of the MBRC. which halves the calculated cost of a tablescan.
Jonathan Lewis 2003-2004

There are a few little traps to costing - whether you use the traditional or new method - Changing the block size for a table will change the cost of scanning

Oracle 10 Evolution 15

Improved tools - Explain Plan


select * from Where and and and t1 id1 = 14 -- index col 1 id3 between 1 and 20 -- index col 3 n1 = 'a' -- tab, number col v1 > 15; -- tab, varchar col
Apart from the new optimisation tricks, Oracle keeps enhancing the tools to let you see what's going on. This is a badly written query.
Oracle 10 Evolution 16

Jonathan Lewis 2003-2004

Improved tools - Explain Plan


select where and and and * from t1 id1 = 14 id3 between 1 and 20 n1 = 'a' v1 > 15; ----index col 1 index col 3 tab, number col tab, varchar col

Search_columns:

Access_predicates (index): (T1.ID1 = 14 AND T1.ID3 >= 1 AND T1.ID3 <= 20)

Jonathan Lewis 2003-2004

Always check for new columns in the plan_table, (utlxplan.sql, catplan.sql). How much of the index goes into the start-key, stop-key calculations.

Oracle 10 Evolution 17

Improved tools - Explain Plan


select where and and and * from t1 id1 = 14 id3 between 1 and 20 n1 = 'a' v1 > 15; ----index col 1 index col 3 tab, number col tab, varchar col

Filter_predicates (index): (T1.ID3 >= 1 AND T1.ID3 <= 20) Filter_predicates (table): (T1.N1=TO_NUMBER('a') AND TO_NUMBER(T1.V1)>15)

Jonathan Lewis 2003-2004

What predicates have to be checked on every single entry from the leaf entry, and table entry. Implicit conversions suddenly become explicit and visible

Oracle 10 Evolution 18

Correlated Subq - revisited


FILTER TABLE ACCESS (FULL) OF EMP (Cost=34 Card=1000) SORT (AGGREGATE) TABLE ACCESS (FULL) OF EMP (Cost=34 Card=1000) FILTER "OUTER. SAL> (SELECT AVG(INNER.SAL) FROM EMP INNER WHERE INNER.DEPT_NO=:B1)" TABLE ACCESS (FULL) OF EMP SORT (AGGREGATE) TABLE ACCESS (FULL) EMP "INNER.DEPT_NO=:B1"

Jonathan Lewis 2003-2004

The unhelpful filter line of the old Oracle 8 plan would become much more meaningful using the new columns in Oracle 9's explain plan

Oracle 10 Evolution 19

Improved tools - V$ Plan


v$sql_plan v$sql_plan_statistics
(last_)CR_BUFFER_GETS (last_)CU_BUFFER_GETS (last_)DISK_READS (last_)DISK_WRITES (last_)ELAPSED_TIME (last_)EXECUTIONS (last_)OUTPUT_ROWS (last_)STARTS

for each line of the plan !

Jonathan Lewis 2003-2004

Not only do you have a better plan_table, you also have real-time excution plans made visible in Oracle 9i - with the actual run-time statistics.

Oracle 10 Evolution 20

10

Correlated Subq - yet again


select outer.* from emp outer where outer.sal > ( select /*+ no_unnest */ avg(inner.sal) from emp inner where inner.dept_no = outer.dept_no ); SELECT STATEMENT FILTER TABLE ACCESS (FULL) OF 'EMP' (TABLE) SORT (AGGREGATE) TABLE ACCESS (FULL) OF 'EMP' (TABLE) (last_)Starts 1 1 6 6

Jonathan Lewis 2003-2004

If we look at the correlated subquery again, we see that the execution plan is not telling us everything - the statistics (starts in particular) are very helpful.

Oracle 10 Evolution 21

Improved tools - tkprof


tkprof {tracefile} {outputfile} waits=yes
-- default

Elapsed times include waiting on following events: Event waited on Times Max Wait Tot Waited ----------------------------- Waited -------- ---------SQL*Net message to client 111 0.00 0.00 SQL*Net message from client 110 83.97 103.47 SQL*Net more data from client 16 0.05 0.13 SQL*Net more data to client 48 0.02 0.05 SQL*Net message to dblink 11 0.00 0.00 SQL*Net message from dblink 11 0.02 0.02 log file sync 3 0.00 0.00

Jonathan Lewis 2003-2004

Oracle 9i also allows you to summarise wait states in a trace file . Generated from a 10046 level 8 trace, or using the improved (legal) sql_trace facility.

Oracle 10 Evolution 22

11

At last we get to ...

10

Jonathan Lewis 2003-2004

Oracle 10 is very different from it predecessors because a huge fraction of the change is about optimising your use of time - not the machine's.

Oracle 10 Evolution 23

Optimiser enhancements (a)


select from where and and and * t1 n1 = 1 n2 = 1 (n3+1 = 1 or n3+1 = 2 or n3+1 = 3); n4 = 1 -- 4-column index

Execution plan from 9i TABLE ACCESS TEST_USER T1 (by index rowid) Filter (T1.N3+1 = 1 OR T1.N3+1 = 2 OR T1.N3+1 = 3) INDEX NON-UNIQUE TEST_USER I1 (range scan) (Columns 3) Access (T1.N1 = 1 AND T1.N2 = 1 AND T1.N4 = 1) Filter (T1.N4 = 1)

Jonathan Lewis 2003-2004

The optimiser is always being enhanced to improve the efficiency at all sort of levels. In 9.2, column n3 is checked only after you get to the table.

Oracle 10 Evolution 24

12

Optimiser enhancements (b)


select from where and and and * t1 n1 = 1 n2 = 1 (n3+1 = 1 or n3+1 = 2 or n3+1 = 3); n4 = 1 -- 4-column index

Execution plan from 10g TABLE ACCESS (analyzed) TABLE TEST_USER T1 (by index rowid) INDEX (analyzed) INDEX TEST_USER I1 (range scan)(Columns 3) Access (N1 = 1 AND N2 = 1 AND N4 = 1) Filter (N4 = 1 AND (N3+1 = 1 OR N3+1 = 2 OR N3+1 = 3))

Jonathan Lewis 2003-2004

On the upgrade to 10g, a query like this might suddenly show a performance improvement because the check of column n3 can now be done in the index.

Oracle 10 Evolution 25

New optimiser options


select from where 0 1 2 3 4 2 3 4 0 1 2 2 1 2 2 count(st.padding),count(lt.padding) small_table,large_table small_table.id(+) = large_table.n1; SELECT STATEMENT SORT (AGGREGATE) HASH JOIN (OUTER) -- v9.2 TABLE ACCESS (FULL) OF 'LARGE_TABLE' TABLE ACCESS (FULL) OF 'SMALL_TABLE' HASH JOIN (RIGHT OUTER) -- 10.1 TABLE ACCESS (FULL) OF 'SMALL_TABLE' TABLE ACCESS (FULL) OF 'LARGE_TABLE'

Jonathan Lewis 2003-2004

Of course, there are inevitably some improvements from coding in new optimisation techniques and execution paths - for example outer hash joins

Oracle 10 Evolution 26

13

New language extensions (1)


select t2.event_id, t1.chk_pt, t2.score from ( t2 partition by (event_id) right join t1 on (t2.chk_pt = t1.chk_pt) ) order by t2.event_id, t1.chk_pt ;

Jonathan Lewis 2003-2004

Oracle has invented, and the ANSI committee has approved, the partiitoned outer join. (Only for use with ANSI outer join syntax, though)

Oracle 10 Evolution 27

New language extensions (2)


t1(chk_pt ...) 1,2,3,4... t2( event_id, chk_pt, score )
EVENT_ID Buffer Buffer Enqueue Enqueue Wait Wait
Jonathan Lewis 2003-2004

EVENT_ID Buffer Buffer Buffer Buffer Enqueue Enqueue Enqueue Enqueue Wait Wait Wait Wait

CHK_PT 1 2 3 4 1 2 3 4 1 2 3 4

SCORE 8

3 10

CHK_PT 1 4 1 4 2 4

SCORE 8 3 10 15 12 17

15

12 17
Oracle 10 Evolution 28

How can you get from the output on the left to the output on the right ? A simple outer join will not do - we need an 'outer join per event id'.

14

Better hints
index (t1, index (t1 i1) v9.2 t1(col1, col2))v10.1 v10.1 v10.1 v9.2 v10.1

no_index_ss (t3) no_index_ffs (t3 i1 i2 i3) leading (t3) leading (t3 t4 t1 t5 t2) The strangest hint in 10g /*+ IGNORE_OPTIM_EMBEDDED_HINTS
Jonathan Lewis 2003-2004

*/

Some of the enhancements are very low key, and yet extremely effective. For example, index hints just got safer, and the leading hint is now really useful.

Oracle 10 Evolution 29

Index coalesce - 8i and 9i


alter index i1 coalesce;

Jonathan Lewis 2003-2004

Under 8i and 9i, the coalesce could only produce a single block from a set of adjacent blocks - so missed many opportunities for improving the index.

Oracle 10 Evolution 30

15

Index coalesce - 10
alter index i1 coalesce;

Jonathan Lewis 2003-2004

Oracle 10 can take a longer stream of index leaf blocks, and distribute the discovered rows more widely. (The branch block restriction still applies)

Oracle 10 Evolution 31

dbms_stats enhancements
procedure alter_stats_history_retention procedure get_stats_history_retention procedure restore_table_stats procedure purge_stats procedure gather_fixed_objects_stats procedure gather_dictionary_stats procedure lock_table_stats procedure unlock_table_stats

Jonathan Lewis 2003-2004

There are plenty of enhancements to investigate in dbms_stats - including analysing the X$ objects, locking statistics, and recalling historical stats.

Oracle 10 Evolution 32

16

Cache hit statistics


INSERT INTO sys.cache_stats_1$( OBJ#, CACHED_SUM, CACHED_VAR, CACHED_NO, CACHED_DATE,LGR_LAST, LGR_SUM,LGR_VAR,LGR_NO, LGR_DATE, PHR_LAST,PHR_SUM, PHR_VAR ) VALUES ( :1,:2,0, CASE WHEN (:2>0) THEN 1 ELSE 0 END, SYSDATE,:3,0,0,0,SYSDATE,:4,0,0 );
Jonathan Lewis 2003-2004

Some information that gets dumped to disc (by mmon) is an extract from v$segstat. This is one of the two ways in which the data is recorded.

Oracle 10 Evolution 33

Cache Hit Ratios resuscitated ?


desc tab_stats$ desc ind_stats$
OBJ# CACHEDBLK CACHEHIT LOGICALREAD NOT NULL NUMBER NUMBER NUMBER NUMBER

Cache history is not currently used - but there are parameters waiting to be set to enable it.
Jonathan Lewis 2003-2004

And one reason the v$segstat data is recorded becomes apparent when you discover the ind_stat$ and tab_stat$ tables, which hold 'local' cache hit ratios

Oracle 10 Evolution 34

17

Parameters now set to TRUE:


_optimizer_correct_sq_selectivity _optimizer_dim_subq_join_sel _optimizer_join_sel_sanity_check _optimizer_squ_bottomup _partition_view_enabled _push_join_union_view2 _right_outer_hash_enable query_rewrite_enabled skip_unusable_indexes
And one that's false: _optimizer_ignore_hints

How much DID you know about join order effects ? _optimizer_join_order_control = 3
There are 46 parameters that change their values if you change the setting for optimizer_features_enabled from 8.1.7.4, through 9.2.0.4 to 10.1.0.2

Jonathan Lewis 2003-2004

Oracle 10 Evolution 35

Undercover optimisation (1)


select user from dual; begin m_user := user; end;
Execution Plan 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2 Card=1) 1 0 FAST DUAL (Cost=2 Card=1) Statistics 0 0 1

db block gets consistent gets rows processed

Jonathan Lewis 2003-2004

For all those over-zealous developers who like to include the username and time in every single procedure - the cost of hitting dual has dropped.

Oracle 10 Evolution 36

18

Undercover optimisation (2)


When 10g sees this
for r1 in (select ... from all_objects)loop -- do something for each row end loop; -- check v$sql.fetches

it does something like this


open c1; -- for select ... from all_objects loop fetch c1 bulk collect into m_array_var limit 100 for i in 1..m_array_var.count loop -- do something for each row end loop; until c1%notfound close c1; end loop;
Jonathan Lewis 2003-2004

Oracle 10g will take an inefficient pl/sql loop like the above 'traditional' form, and operate as if it were written in the 'array processing form'.

Oracle 10 Evolution 37

Undercover Optimisation (3)


for i_ct in 1..10000 loop execute immediate 'select spare from parse_table where id = :v1' into m_dummy using i_ct; end loop; Latch: shared pool library cache library cache pin Statistic: parse count (total) session cursor cache hits open cursors cumulative
Jonathan Lewis 2003-2004

9.2.0.4 30,000 60,000 60,000 9.2.0.4 10,000 10,000 10,000

10.1.0.2 20,000 40,000 40,000 10.1.0.2 10,000 10,000 (15)


Oracle 10 Evolution 38

Using "execute immediate' to build strings in a pl/sql function is a popular method. The SQL doesn't get into the pl/sql cursor cache - until verion 10g.

19

Undercover Optimisation (4)


for i in 1..10 loop begin insert into t1 values (i,i,i,i); end; end loop;
Redo Redo Redo Redo Redo entries size copy latch (immediate) allocation latch(willing to wait) allocation latch (immediate) 9.2.0.4 50 10,880 50 50 ..

-- 4 indexes

10.1.0.2 0 0 0 0 ..

Alert log: Running with 1 shared and 18 private strand(s).


Oracle 10g uses 'private redo threads'. For small transactions, Oracle delays publishing the redo. This reduces redo record count, overhead and latching.

Jonathan Lewis 2003-2004

Oracle 10 Evolution 39

Structural optimisation (1)


create table t1 (n1 number, v1 varchar2(10)) partition by range (n1) ( partition p001 values less than (1),
...

partition p199 values less than (199) ); alter table t1 drop partition p001; update tabpart$ set part# = :1 where obj# = :2 and bo# = :3
call Parse Execute Fetch total count 198 198 0 396 cpu 0.01 0.10 0.00 0.11 elapsed 0.01 0.06 0.00 0.08 disk 0 0 0 0 query 0 199 0 199 current 0 202 0 202 rows 0 198 0 198

Jonathan Lewis 2003-2004

If you've ever dropped a partition from a partitioned table with a very large number of partitions, you may have noticed it takes some time. Trace it.

Oracle 10 Evolution 40

20

Structural optimisation (2)


select obj#, part# from tabpart$ where bo# = {table object id}; Results 9.2.0.4
OBJ# 48008 48011 48013 48015 48017 PART# 1 2 3 4 5

Results 10.1.0.2
OBJ# 54815 54818 54820 54822 54824 PART# 10 20 30 40 50

select -- view tabpartv$ obj#, dataobj#, bo#, row_number() over (partition by bo# order by part#), etc from tabpart$
Jonathan Lewis 2003-2004

10g does it better; and when you check the data dictionary content, and the view definitions for the two versions, you find out why.

Oracle 10 Evolution 41

Tuning Advisor
select /*+ example 1 */ padding from t1 where n1 = 15; select /*+ example 2 */ {list of columns} from t1, t2 where t2.n2 = 15 and t2.n1 = 15 and t1.n2 = t2.n2 and t1.n1 = t2.n1 ; select /*+ example 3 */ n2 from t1 where n1 not in (select n1 from t2) ;
Possibly the most significant benefit of 10g is the tool that allows you to ask Oracle to find better optimisation paths for your SQL - like these examples.

Jonathan Lewis 2003-2004

Oracle 10 Evolution 42

21

22

23

Tuning Advisor (1a)


Benefit 99.66% Findings The execution plan of this statement can be improved by creating one or more indices. Recommendations Consider running the Access Advisor to improve the physical schema design or creating the recommended index.

Jonathan Lewis 2003-2004

Apart from suggesting that an index would be appropriate, and giving an indication of the benefit, you can ask to see the resulting execution plan

Oracle 10 Evolution 48

24

Tuning Advisor (1b )


Rationale Creating the recommended indices significantly improves the execution plan of this statement. However, it might be preferable to run "Access Advisor" using a representative SQL workload as opposed to a single statement. This will allow to get comprehensive index recommendations which takes into account index maintenance overhead and additional space consumption.

Jonathan Lewis 2003-2004

Most importantly, each recommendation comes with a Rationale. The bit I particularly like is the reminder to test with a representative workload.

Oracle 10 Evolution 49

25

Not necessarily a bad thing.

26

Tuning Advisor (2a)


Benefit 80.97% Findings A potentially better execution plan was found for this statement. Recommendations Consider accepting the recommended SQL profile. execute :profile_name := dbms_sqltune.accept_sql_profile( task_name => 'TASK_3201' )
On a different statement the advisor says it can't help me with the code, but it has produced a Profile (a bit like an Outline) that will help if enabled.

Jonathan Lewis 2003-2004

Oracle 10 Evolution 54

27

Tuning Advisor (2b)


select {columns} from dba_sql_profiles;
NAME CATEGORY STATUS SQL_TEXT select : SYS_SQLPROF_040624083819387 : DEFAULT : ENABLED : count(t1.v1) ct_v1, count(t2.v1) ct_v2 ...

from

dbms_sqltune.drop_sql_profile('SYS_SQLPROF_040624083819387');

Jonathan Lewis 2003-2004

If you accept a profile, you can see it in the view dba_sql_profiles. You cannot see what it is doing, though. But you can gets its identify to drop it.

Oracle 10 Evolution 55

Tuning Advisor (2c)


Profiles can hold enhanced statistics:
OPT_ESTIMATE(@"SEL$1", TABLE, "T2"@"SEL$1", SCALE_ROWS=15) Table T2 will return 15 times as many rows as expected OPT_ESTIMATE( @"SEL$1", JOIN, ("T2"@"SEL$1", "T1"@"SEL$1"), SCALE_ROWS=15 ) The join T2 -> T1 will return 15 times as many rows as expected
Profiles often hold enhanced statistics to help the optimiser calculate costs more accurately. Unlike outlines, they do not hold a fixed path definition.

Jonathan Lewis 2003-2004

Oracle 10 Evolution 56

28

Tuning Advisor (3a)


Findings The optimizer could not unnest the subquery at line ID 1 of the execution

Recommendations Consider replacing "NOT IN" with "NOT EXISTS" or ensure that columns used on both sides of the "NOT IN" operator are declared "NOT NULL" by adding either "NOT NULL" constraints or "IS NOT NULL" predicates.

Jonathan Lewis 2003-2004

In this case, the optimizer cannot do an internal rewrite and guarantee the results - but tells me that if I enforce some constraints, a rewrite is possible.

Oracle 10 Evolution 58

29

Tuning Advisor (3b)


Rationale A "FILTER" operation can be very expensive because it evaluates the subquery for each row in the parent query. The subquery, when unnested can drastically improve the execution time because the "FILTER" operation is converted into a join. Be aware that "NOT IN" and "NOT EXISTS" might produce different results for "NULL" values.

Jonathan Lewis 2003-2004

In this case, the rationale even goes so far as to teach you something about how SQL works. The warning is one that some 'gurus' don't seem to know.

Oracle 10 Evolution 59

Conclusion
New features can improve application performance New kernel code improves the database performance New tools improve your performance

Jonathan Lewis 2003-2004

Oracle 10 Evolution 60

30

You might also like