Upload
solarwinds
View
267
Download
4
Embed Size (px)
Citation preview
Stop the Chaos! Get Real Oracle Performance by Query Tuning – Part 2Janis Griffin
Senior DBA / Performance Evangelist
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Who am I?
• Senior DBA / Performance Evangelist for SolarWinds• [email protected]• Twitter® - @DoBoutAnything• Current – 25+ Years in Oracle®, DB2®, ASE, SQL Server®, MySQL®• DBA and Developer
• Specialize in performance Tuning• Review database performance for customers and prospects• Common question: “How do I tune it?”
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Agenda
• A quick review of part 1• Using wait time analysis (WTA)• Reviewing the execution plan
• Understanding the optimizer• Finding the expensive steps
• Discuss several tuning techniques• SQL diagramming• Partitioning and other useful features
• How to identify coding mistakes • Engineer out the stupid
• What to do if you can’t change the code• Third-party applications• Avoiding hints
• Who registered yesterday for SQL Tuning?
SELECT s.fname, s.lname, r.signup_dateFROM student s
INNER JOIN registration r ON s.student_id = r.student_idINNER JOIN class c ON r.class_id = c.class_id
WHERE c.name = 'SQL TUNING'AND r.signup_date BETWEEN :beg_date AND :end_dateAND r.cancelled = 'N‘
• Execution Stats – 21,829 Buffer Gets• Execution Time – 22 seconds to execute• Wait Events – Waits 90% direct path read
Case Study for Review
User
complained.
Query spent
over 3 hours in
the database.© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Execution Plan
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Relationship Diagram
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• Recommends – three new indexes
Tuning Advisor
DECLARE
l_sql_tune_task_id VARCHAR2(100);
BEGIN
l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task ( sql_id => '&sql_id',
scope => DBMS_SQLTUNE.scope_comprehensive, time_limit => 60,
task_name => '&sql_id', description => 'Tuning task for class registration query');
DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id);
END;
/
EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => '&sql_id');
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• Need to know the size of the actual data sets for each step in execution plan• In Joins (Right, Left, Outer)• What are the filtering predicates?• When is each filtering predicate applied?
• Try to filter earlier rather than later
• Compare size of final result set with data read• Find the driving table
• To reduce buffer gets
Tune the Query
SELECT s.fname, s.lname, r.signup_date
FROM student s
INNER JOIN registration r ON s.student_id = r.student_id
INNER JOIN class c ON r.class_id = c.class_id
WHERE c.name = 'SQL TUNING'
AND r.signup_date BETWEEN :beg_date AND :end_date
AND r.cancelled = 'N'
Joins
Filtering
Predicates
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• “SQL Tuning” by Dan Tow• Great book that teaches SQL Diagramming• http://www.singingsql.com
SQL Diagramming
registration
student class
5
1
30
1
4%
.1%
select count(1) from registration where cancelled = 'N'
and signup_date between '2016-12-10 00:00' and '2016-12-11 00:00'
64112 / 1783066 * 100 = 3.59 or 4%
select count(1) from class where name = 'SQL TUNING'
2 / 1,267 * 100 = .1%
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• CREATE INDEX cl_name ON class(name);
• Execution Stats – 20,348 buffer gets• Why is a full table scan still occurring on REGISTRATION?
New Execution Plan
• CLASS_ID not left leading in index
• Execution Stats – 20,348 buffer gets• Twice the work to use Primary Key Index on REGISTRATION
Review Index Order
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• CREATE INDEX reg_alt ON registration(class_id);
• Execution Stats – 3000 Buffer Gets / Average Execs - .008 Secs
New Execution Plan
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• CREATE INDEX reg_cancel_signup ON registration(cancelled,signup_date);
Tuning Advisor Suggested Index
Execution Stats:
1107 Buffer Gets
Avg Executions:
0.140 Secs
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• CREATE INDEX reg_alt ON registration(class_id,signup_date, cancelled);
• Execution Stats – 445 Buffer Gets / Average Execs - .002 Secs
Better Execution Plan
Performance Improved
reg_canceled_signup index
Average Wait Time per Execution for SQL Statement Class_Registration | CECE_JGRIFFIN-2
January 27, 2015
Daily Time Range: 1:00 PM-10:00 PM
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Case Study – Current Pay Check For Specific Employees
SELECT e.first_name, e.last_name, l.region_name
FROM emp e
INNER JOIN dept d ON e.department_id = d.department_id
INNER JOIN loc l ON l.location_id = d.location_id
WHERE (e.last_name LIKE :b1)
AND e.employee_id IN (
SELECT employee_id
FROM wage_pmt w
WHERE w.employee_id = e.employee_id
AND w.pay_date>= trunc(sysdate)-31);
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Wait Time Analysis
Almost 100% on PGA
memory allocation wait. New
wait event in 12.2 – not
documented
No statistics,
Unique indexes
Added PKs and Fks
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Execution Plan
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Understanding the Underlying Objects
ACCEPT SQL_ID CHAR PROMPT 'Enter SQL_ID> 'DECLAREl_sql_tune_task_id VARCHAR2(100);
BEGINl_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task ( sql_id => '&sql_id',scope => DBMS_SQLTUNE.scope_comprehensive, time_limit => 60,task_name => '&sql_id', description => 'Tuning task for Current Paycheck');DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id);
END;/EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => '&sql_id');SELECT DBMS_SQLTUNE.report_tuning_task('&sql_id') AS recommendations FROM dual;EXEC DBMS_SQLTUNE.drop_tuning_task('&sql_id');
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Ask the Tuning Advisor
No recommendations
SQL Diagramming
select count(1) from wage_pmt
where pay_date >= sysdate – 31
2,184 / 142,708 * 100 = 1.5%
select avg(cnt) from (select substr(last_name,1,3), count(*) cnt
from emp group by substr(last_name,1,3))
278.5 / 3,899 * 100 = .7.14% With full last nume = .1%
emp
dept
wage_pmt
975
1
37
1
.7%
2%
loc1
1
.1%
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
No change?
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Add Index on WAGE_PMT(employee_id)
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Adjust Index on WAGE_PMT
CREATE INDEX idx_emp_dateON wage_pmt(employee_id, pay_date);
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Improved Performance
Created index
IDX_EMP_DATE
• FETCH FIRST n ROWS ONLY • Retrieves first rows without scanning everything• Faster than using rownum
• OFFSET n ROWS FETCH FIRST n ROWS ONLY• Skip some number of rows
• 12.2 Approximate Query Processing• Used for approximate ‘count distinct’ values
• And adds percentile aggregation
• Allows for faster processing of large data sets• Not exact but usually within 95%+ range
• Three new parameters – alter system/session • approx_for_aggregation Default=FALSE• approx_for_count_distinct Default=FALSE• approx_for_percentile Default=NONE
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Other Tuning Tips
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Approximate SQL Example Without Changing Code
Why is it exact?
Need to
set both
• Convert non-partitioned table • To a partitioned table ONLINE
• Many new partition options• Automatic Lists• Multi-column Lists• Partitioned external tables• Other maintenance options
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
New 12.2 Partitioning Features
UPDATE INDEXES clause is
optional. Indexes with SYS
names will be generated if not
used.
• Look for performance inhibitors• Cursor or row by row processing • Parallel processing
• Don’t use in an OLTP environment• Use only when accessing large data sets and additional resources can be allocated
• Nested views that use db_links• Abuse of Wild Cards (*) or No Where Clause
• Select ONLY those columns in a query which are required. • Extra columns cause more I/O on the database and increase network traffic• Code-based SQL Generators (e.g. Hibernate)
• Using functions on indexed columns (SUBSTR, TO_CHAR, UPPER, TRUNC)• Optimizer can’t use the index
• Instead move the function to the constant or variable side of equation• Consider creating a function based index
• Hard-coded hints
Engineer Out the Stupid
select… where upper(last_name) = ‘GRIFFIN’
Better way: select … where last_name = upper(:b1);
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• Reduce SORT operations as they slow down your queries• Don’t use the UNION operator if you can use UNION ALL• Avoid the DISTINCT keyword if you don’t need it
• Ensure the left-leading column of a multi-column index is reference• Otherwise an INDEX SKIP SCAN may occur
• Often no better than a FULL TABLE SCAN
• Try to avoid Cartesian product queries• Use bind variables instead of literal values
• Reduces repeated parsing of the same statement
• If using sub-queries, make use of the EXISTS operator when possible• Optimizer will stop with a match and avoid a FULL TABLE SCAN
• Try to use an index if less than 5% of the data needs to be accessed• Exception: small table are best accessed through a FULL TABLE SCAN
• Consider keeping in memory
More Do’s and Don’ts
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• Use equi-joins whenever possible• Try not to use ‘not in’, !=, <>, not null, etc.• Optimizer has more choices to choose from
• Avoid complex expressions such as NVL(col1,0), TO_DATE(), TO_NUMBER()• They prevent the optimizer from assigning valid cardinality or selectivity estimates • Can affect the overall plan and the join methods
• Avoid joining complex views• May instantiate all views to run query against (reading too much data)• Querying views requires all tables from the view to be accessed
• If they aren’t required, then don’t use the view
• Use the partition key in the ‘WHERE’ clause if querying a partitioned table • Partition pruning will be used to reduce the amount of data read
Avoid Common Pitfalls
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• If you can hint it, baseline it (per Tom Kyte)• Alternative to using hints
• Hints difficult to manage over time• Once added, usually forgotten about
• Third-party software – can’t modify code• Example:Merge Join Cartesian > Nested Loop
select /* jg */ p.product_name
from order_items o, product p
where o.unit_price = :b1
and o.quantity > :b2
and o.product_id = p.product_id
and p.product_id = :b3;
What to Do If You Can't Change the Query
select /*+ USE_NL(o p) */ /* jg */ p.product_name
from order_items o, product p
where o.unit_price = :b1
and o.quantity > :b2
and o.product_id = p.product_id
and p.product_id = :b3;
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• Create baseline of original planAlter session set optimizer_capture_sql_plan_baselines = TRUE;• Or dbms_spm.load_plans_from_cursor_cache
• Example next slide
How to Change the Baseline
From cache Baseline
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• Manually run hinted query• Hint = /*+ USE_NL(p) +/
Change the Baseline – Cont.
Get SQL_ID, Plan hash value from cache Load from cache into baseline
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
SELECT c_last, c_first, c_street_1, c_city, c_state, c_zip,c_phone, o_entry_d, d_name, ol_delivery_d, ol_quantity, ol_amount
FROM order_line, orders, district, customer, stockWHERE o_id = ol_o_idAND o_c_id=c_idAND s_i_id = ol_i_idAND d_id = ol_d_idAND ol_w_id = :B2AND ol_d_id = :B4AND (ol_o_id < :B3 )AND ol_o_id >= (:B3 - 20)AND s_w_id = :B2AND s_quantity < :B1AND d_id = :B4AND c_last like :B5 ;
Another Case Study – Orders by Customer Last Name
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Review the Execution Plan
select * from table (dbms_xplan.display_cursor(null,null, format=> '+report'));
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• Stock:
Get Object Information
create index stock_idx
on stock
(s_i_id, s_w_id, s_quantity);
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• Orders:
Get Object Information
Actual Rows = 60,000
Find the Driving Table
orders
stock
district
100
130
1
.7%
.03
select count(*) from order_line
where ol_o_id < 200 and ol_o_id >= 200-20;
3941 / 600916 * 100 = .6558%
select avg(cnt) from (select c_last, count(*) cnt
from customer group by c_last);
20 / 60000 * 100 = .03333%
Filter on Stock: 3109 / 283000 * 100 = 1%
order_line
customerwarehouse
WHERE o_id = ol_o_id
AND o_c_id=c_id
AND s_i_id = ol_i_id
AND d_id = ol_d_id
AND ol_w_id = :B2
AND ol_d_id = :B4
AND (ol_o_id < :B3 )
AND ol_o_id >= (:B3 - 20)
AND s_w_id = :B2
AND s_quantity < :B1
AND d_id = :B4
AND c_last like :B5 ;
1
20
1
1
660092
10
1%
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
• create index stock_idx on stock (s_i_id, s_w_id, s_quantity);
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Engineer Out the Stupid
• create index orders_i2 on orders(o_id,o_c_id, o_entry_d);
Add Index on Orders to INCLUDE Customer
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Did Performance Improve?
Added Index on
Stock
Added Index on
Orders
• Make sure you are tuning the correct query• Use wait time analysis
• Understand the execution plan • Focus on the costly steps• Know what the optimizer knows
• Try these tuning techniques • SQL diagraming to find the best execution plan• Consider new fetch, approximate and partitioning features
• Engineer out the stupid• Be on the lookout for coding mistakes
• If you can’t change the code• Try using baselines or patches
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Summary
• Try Database Performance Analyzer FREE for 14 days• Improve root cause of slow performance
• Quickly identify root cause of issues that impact end-user response time• See historical trends over days, months, and years• Understand impact of VMware® performance • Agentless architecture with no dependence on Oracle Packs, installs in minutes
© 2017 SolarWinds Worldwide, LLC. All rights reserved.
Resolve performance issues quickly - free trial
www.solarwinds.com/dpa-download/
The SolarWinds, SolarWinds & Design, Orion, and THWACK trademarks are the exclusive
property of SolarWinds Worldwide, LLC or its affiliates, are registered with the U.S.
Patent and Trademark Office, and may be registered or pending registration in other
countries. All other SolarWinds trademarks, service marks, and logos may be common
law marks or are registered or pending registration. All other trademarks mentioned
herein are used for identification purposes only and are trademarks of (and may be
registered trademarks) of their respective companies.
Thank You!!!