You are on page 1of 66

An

Embarcadero Oracle Community Webinar

Making Impac,ul Performance Changes


Karen Morton Sr. Technical Consultant

karen.morton@enkitec.com karenmorton.blogspot.com karen_morton

July 31 Diagnosing SQL Performance Problems August 29 Making SQL Performance SoluIons SIck September 26 Making Impac,ul Performance Changes
3

Topics
Common ways to rewrite SQL to make it perform beNer and more consistently How and when to index
AddiIons or modicaIons to provide best soluIon

About SQL Tuning Advisor


When it helps When it doesn't

Rewriting SQL

First things rst


(This stu is really important)

Review the statement.


What is it

supposed

to do?

Tune the quesIon, not the query. Tom Kyte

Collect data.

Review staIsIcs.

Check

indexes
and

constraints.

Execute
the query.

Evaluate
the plan.
(compare esImates to actuals)

big hiNers?

Where are the

the statement.
(if you should)

Refactor

indexes, constraints, staIsIcs.


(if you should)

Modify or Add

T T D
(Test To DestrucIon)

Iterate
unIl target met or no further improvement possible

Things To Keep In Mind

How do you do simple, yet eecIve, tesIng?

Name your SQL


SELECT /* kmtest */ FROM tab

/*+ gather_plan_staIsIcs */
(staIsIcs_level = ALL)

dbms_xplan.display_cursor
('ALLSTATS LAST')

SELECT xplan.*! FROM ! (! select max(sql_id) keep! (dense_rank last order by last_active_time) sql_id! , max(child_number) keep! (dense_rank last order by last_active_time) child_number! from v$sql! where upper(sql_text) like '%&1%'! and upper(sql_text) not like ! ! !'%FROM V$SQL WHERE UPPER(SQL_TEXT) LIKE %'! ) sqlinfo,! table(DBMS_XPLAN.DISPLAY_CURSOR! (sqlinfo.sql_id, sqlinfo.child_number, 'ALLSTATS LAST')) xplan ;! ! ! -- +COST +BYTES +PEEKED_BINDS!

/*+ monitor */

dbms_sqltune.report_sql_monitor
(TEXT, HTML, XML, ACTIVE)

SELECT dbms_sqltune.report_sql_monitor! (! ! !SQL_ID => '&sql_id', ! ! !SESSION_ID => '&session_id',! ! !SESSION_SERIAL => '&session_serial',! ! !TYPE => '&report_format'! ) ! FROM dual ;!

Monitored statements can be found in V$SQL_MONITOR

Know thy data.


(and thy schema)

(Visual SQL Tuning)

Visualize

output from Embarcadero DB OpImizer

How do you know when rewriIng SQL is the

best opIon?
33

Look for "column-less" joined tables.

This

SELECT FROM WHERE AND


Becomes

b.* a, b a.col1 = b.col1 b.col2 = <condition>

SELECT FROM WHERE AND FROM a

b.* b b.col2 = <condition> EXISTS (SELECT null WHERE a.col1 = b.col1)

Look for improper outer joins.

This

AND tab1.col1 = tab2.col1 (+) AND tab2.col2 = <condition>

Becomes

AND tab1.col1 = tab2.col1 AND tab2.col2 = <condition>


Because the condiIon would be null for the outer joined row, so the predicate could never be true.

Look for repeated use of same tables and predicates.

SELECT rite.event_name, count(*) FROM riffs.rf_order ro, riffs.rf_order_item roi, riffs.rf_item_transaction rit, riffs.rf_item_transaction_event rite WHERE ro.is_test = '0' AND ro.order_id = roi.order_id AND roi.order_item_id = rit.order_item_id AND roi.order_id = rit.order_id AND rit.transaction_id = rite.transaction_id AND (rite.event_name >'AUTHORIZED' OR rite.event_name <'AUTHORIZED') GROUP BY rite.event_name UNION ALL SELECT 'TRANSACTION_INITIATED', count(*) FROM (SELECT count(*) FROM riffs.rf_order ro, riffs.rf_order_item roi, riffs.rf_item_transaction rit, riffs.rf_item_transaction_event rite WHERE ro.is_test = '0' AND ro.order_id = roi.order_id AND roi.order_item_id = rit.order_item_id AND roi.order_id = rit.order_id AND rit.transaction_id = rite.transaction_id AND rite.event_name = 'AUTHORIZED' GROUP BY substr(rit.TRANSACTION_ID,1,INSTR(rit.TRANSACTION_ID,'_')-1))

Look for simple predicates ORed with other predicates in ranges.

This

AND col1 > <condition> OR col2 > <condition>

Becomes

AND col1 > <condition> UNION / UNION ALL AND col2 > <condition>
Because a row could not be rejected when one predicate is false without checking the other predicates.

Look for DISTINCT/UNION to remove duplicates.


Consider using IN or EXISTS instead.

Check viability of indexes.

Do indexes provide proper coverage?

How and When to Index

44

For many years, inadequate indexing has been the most common cause of performance disappointments.

Tapio Lahdenmki

45

Indexing Problems
Indexes that do not have sucient columns to support all predicates Not enough indexes present
Numerous single-column but few mulI-column

Indexes with the right columns but in the wrong order

46

How many is "too" many?

47

Heavy DML? Large, bulk loads? or Mostly query?


48

Indexes support query performance

49

Inadequate Index
SELECT !cust_id, cust_first_name! FROM ! !customers! ! WHERE ! !cust_last_name = 'Ruddy'! AND ! ! !cust_city = 'Ede'! ORDER BY cust_first_name ;!

Index present on CUST_LAST_NAME, CUST_FIRST_NAME # rows in table = 55,500

50

Note the number of rows that are thrown away in step 1 (79).

51

Index on CUST_LAST_NAME, CUST_CITY No throwaway

Index on CUST_CITY, CUST_LAST_NAME, CUST_FIRST_NAME, CUST_ID No throwaway, no sort

52

Index Strategies
All columns from equality predicates Add columns used in ORDER BY Add all remaining columns from column list
A 3 star index is owen called a "fat" index. Range predicates are typically placed awer 1 and 2 star columns.
53

The key to determining an ideal index

The index should provide adequate enough screening to minimize table accesses.

54

SQL Tuning Advisor

55

What STA Can Recommend


CollecIon of staIsIcs
Objects with stale or missing staIsIcs are idenIed and appropriate recommendaIons are made to remedy the problem

CreaIon of new indexes


Indexes that can "signicantly" enhance performance

56

What STA Can Recommend


Restructuring of the SQL statement CreaIon of a SQL prole
Remedy execuIon plan ineciencies with a SQL prole

57

Great for poinIng out the "obvious".

Finds the low-hanging fruit.

SQL Restructuring Example 1


Finding: An expensive cartesian product operaIon was found at line ID 2 of the execuIon plan. RecommendaIons: Consider removing the disconnected table or view from this statement or add a join condiIon which refers to it. RaIonale: A cartesian product should be avoided whenever possible because it is an expensive operaIon and might produce a large amount of data.
59

SQL Restructuring Example 2


Finding: The opImizer could not unnest the subquery at line ID 1 of the execuIon plan. RecommendaIons: 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.

60

SQL Restructuring Example 2


RaIonale: A "FILTER" operaIon can be very expensive because it evaluates the subquery for each row in the parent query. The subquery, when unnested can drasIcally improve the execuIon Ime because the "FILTER" operaIon is converted into a join. Be aware that "NOT IN" and "NOT EXISTS" might produce dierent results for "NULL" values.

61

SQL Proles use OPT_ESTIMATE hints.


"Fudge factors"

Not a subsItute for human intelligence.

Monkey vs. Astronaut

Recap
Look for common anI-paNerns in SQL Gather enough diagnosIc data to know where the problem originates Learn what the opImizer expects (and give it what it wants!) Think about your indexing strategy Design indexes for opImal coverage Use STA as a pointer to problems, not necessarily as the soluIon
64

Q & A
65

Thank you!