SlideShare a Scribd company logo
SQL Query Tuning Tips for Oracle
Get it Right the First Time
Dean Richards
Lead DBA, Confio Software
2/21/2013 1
2/21/2013 Confidential - Internal Use Only 2
Who Am I?
• 20+ Years in Oracle & SQL Server
– DBA and Developer
– Worked for Oracle SPG
• Lead DBA for Confio Software
– DeanRichards@confio.com
– Makers of Ignite8 Response Time Analysis Tools
– http://www.ignitefree.com – only free RTA Tool
• Specialize in Performance Tuning
2/21/2013 3
Agenda
• Introduction
• Which Query Should I Tune?
• Query Plans
• SQL Diagramming
– Who registered yesterday for Tuning Class
– Check order status
2/21/2013 Confidential - Internal Use Only 4
Why Focus on Queries
• Most Applications
– Read and Write data to/from database
– Simple manipulation of data
– Deal with smaller amounts of data
• Most Databases
– Examine larger amounts of data, return a little
– Inefficiencies quickly become bottleneck
• Why do SQL tuning?
– Tuning SQL - “Gives the most bang for your buck”
– Changes to SQL are Safer
– ~85% of performance issues are SQL related
2/21/2013 Confidential - Internal Use Only 5
Who Should Tune
• Developers?
– Developing applications is very difficult
– Typically focused on functionality
– Not much time left to tune SQL
– Do not get enough practice
– SQL runs differently in Production than Dev/Test
• DBA?
– Do not know the code like developers do
– Focus on “Keep the Lights On”
– Very complex environment
• Need a team approach
– But also need someone to lead the effort
2/21/2013 Confidential - Internal Use Only 6
Which SQL
• User / Batch Job Complaints
• Queries Performing Most I/O (LIO, PIO)
• Queries Consuming CPU
• Queries Doing Full Table Scans
• Known Poorly Performing SQL
• Tracing a Session / Process
• Highest Response Times (Ignite for Oracle)
select sql_text, elapsed_time, cpu_time, executions,
sql_id, hash_value, last_active_time,
plan_hash_value, program_id, module, action
from v$sql
order by elapsed_time
/
2/21/2013 Confidential - Internal Use Only 7
SQL Wait States
 Understand the total time a Query spends in Database
 Measure time while Query executes
 SQL Server helps by providing Wait Types
Focus on Response Time
2/21/2013 Confidential - Internal Use Only 8
Oracle Wait Interface
V$SQL
SQL_ID
SQL_FULLTEXT
V$SESSION
SID
USERNAME
SQL_ID
PROGRAM
MODULE
ACTION
PLAN_HASH_VALUE
ROW_WAIT_OBJ#
V$SQLAREA
SQL_ID
EXECUTIONS
PARSE_CALLS
BUFFER_GETS
DISK_READS
V$SESSION_WAIT
SID
EVENT
P1, P1RAW, P2, P2RAW, P3, P3RAW
STATE (WAITING, WAITED…)
• Oracle 10g added this info to V$SESSION
V$SQL_PLAN
SQL_ID
PLAN_HASH_VALUE
DBA_OBJECTS
OBJECT_ID
OBJECT_NAME
OBJECT_TYPE
2/21/2013 Confidential - Internal Use Only 9
Oracle Wait Interface
SELECT s.sql_id, sql.sql_text, sql.plan_hash_value,
DECODE(s.state, 'WAITING', s.event, 'CPU/LogicalIO') waitevent,
s.p1, s.p2, s.p3
FROM v$session s, v$sql sql
WHERE s.sql_id = sql.sql_id
AND s.sql_address = sql.address
AND program = ‘…’ AND s.sid = …
AND <whatever else you know>
2/21/2013 Confidential - Internal Use Only 10
SQL Plan
• EXPLAIN PLAN
– Estimated execution plan
– Can be wrong for many reasons
– What most tools show you
• V$SQL_PLAN (Oracle 9i+)
– Real execution plan
– Use DBMS_XPLAN for display
• Confio Ignite for Oracle
– Gathers real plan
– Shows it historically
2/21/2013 Confidential - Internal Use Only 11
DBMS_XPLAN
select * from table (
dbms_xplan.display_cursor(‘&SQLID’,ChildNo));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID f7jqysdfu2f2s, child number 0
-------------------------------------
update emp set hire_date = to_date(':1') where id=:2
Plan hash value: 1494045816
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | | | 3025 (100)| |
| 1 | UPDATE | EMP | | | | |
|* 2 | TABLE ACCESS FULL| EMP | 122 | 2684 | 3025 (1)| 00:00:37 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ID"=3247)
2/21/2013 Confidential - Internal Use Only 12
All Plans Not Equal
SELECT company, attribute FROM data_out WHERE segment = :B1
• Wait Time – 100% on “db file scattered read”
• Plan from EXPLAIN PLAN
• Plan from V$SQL_PLAN using DBMS_XPLAN
2/21/2013 Confidential - Internal Use Only 13
Bind Values
• V$SQL_BIND_CAPTURE
– STATISTICS_LEVEL = TYPICAL or ALL
– Collected at 15 minute intervals
SELECT name, position, datatype_string, value_string
FROM v$sql_bind_capture
WHERE sql_id = '15uughacxfh13';
NAME POSITION DATATYPE_STRING VALUE_STRING
----- ---------- --------------- ------------
:B1 1 BINARY_DOUBLE 189
• Bind Values also provided by tracing
– Level 4 – bind values
– Level 8 – wait information
– Level 12 – bind values and wait information
2/21/2013 Confidential - Internal Use Only 14
Case Studies
• SQL Diagramming
• Case Study 1
– Who registered for Tuning Class yesterday
• Case Study 2
– Check order status
2/21/2013 Confidential - Internal Use Only 15
Case Study 1
• Who registered yesterday for SQL Tuning
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 :1 AND :2
AND r.cancelled = 'N'
• Execution Stats – 12,634 Logical Reads
2/21/2013 Confidential - Internal Use Only 16
Database Diagram
2/21/2013 Confidential - Internal Use Only 17
Execution Plan
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 819 | 3173 (5)| 00:00:39 |
|* 1 | FILTER | | | | | |
| 2 | NESTED LOOPS | | | | | |
| 3 | NESTED LOOPS | | 7 | 819 | 3173 (5)| 00:00:39 |
|* 4 | HASH JOIN | | 7 | 448 | 3166 (5)| 00:00:38 |
|* 5 | TABLE ACCESS FULL | CLASS | 1 | 45 | 22 (0)| 00:00:01 |
|* 6 | TABLE ACCESS FULL | REGISTRATION | 8334 | 154K| 3144 (5)| 00:00:38 |
|* 7 | INDEX UNIQUE SCAN | PK_STUDENT | 1 | | 0 (0)| 00:00:01 |
| 8 | TABLE ACCESS BY INDEX ROWID| STUDENT | 1 | 53 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TRUNC(SYSDATE@!-1)<=TRUNC(SYSDATE@!))
4 - access("R"."CLASS_ID"="C"."CLASS_ID")
5 - filter("C"."NAME"='SQL TUNING')
6 - filter("R"."SIGNUP_DATE">=TRUNC(SYSDATE@!-1) AND "R"."CANCELLED"='N' AND
"R"."SIGNUP_DATE"<=TRUNC(SYSDATE@!))
7 - access("S"."STUDENT_ID"="R"."STUDENT_ID")
2/21/2013 Confidential - Internal Use Only 18
SQL Diagramming
registration
student class
5
1
30
1
.03
.001
select count(1) from registration where cancelled = 'N'
and signup_date between '2012-12-05 00:00' and '2012-12-06 00:00'
54,554 / 1,639,186 = 0.03
select count(1) from class where name = 'SQL TUNING'
2 / 1,267 = .001
• Great Book - “SQL Tuning” by Dan Tow
– Teaches SQL Diagramming
– http://www.singingsql.com
2/21/2013 Confidential - Internal Use Only 19
New Execution Plan
• Execution Stats – 11,168 Logical Reads
• Why does a Full Table Scan still occur on REGISTRATION?
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 819 | 3153 (5)| 00:00:38 |
|* 1 | FILTER | | | | | |
| 2 | NESTED LOOPS | | | | | |
| 3 | NESTED LOOPS | | 7 | 819 | 3153 (5)| 00:00:38 |
|* 4 | HASH JOIN | | 7 | 448 | 3146 (5)| 00:00:38 |
| 5 | TABLE ACCESS BY INDEX ROWID| CLASS | 1 | 45 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | CL_NAME | 1 | | 1 (0)| 00:00:01 |
|* 7 | TABLE ACCESS FULL | REGISTRATION | 8334 | 154K| 3144 (5)| 00:00:38 |
|* 8 | INDEX UNIQUE SCAN | PK_STUDENT | 1 | | 0 (0)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID | STUDENT | 1 | 53 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
CREATE INDEX cl_name ON class(name)
2/21/2013 Confidential - Internal Use Only 20
Database Diagram
2/21/2013 Confidential - Internal Use Only 21
New Execution Plan
CREATE INDEX reg_alt ON registration(class_id)
• Execution Stats – 4,831 Logical Reads
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 819 | 2415 (1)| 00:00:29 |
|* 1 | FILTER | | | | | |
| 2 | NESTED LOOPS | | | | | |
| 3 | NESTED LOOPS | | 7 | 819 | 2415 (1)| 00:00:29 |
| 4 | NESTED LOOPS | | 7 | 448 | 2408 (1)| 00:00:29 |
| 5 | TABLE ACCESS BY INDEX ROWID| CLASS | 1 | 45 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | CL_NAME | 1 | | 1 (0)| 00:00:01 |
|* 7 | TABLE ACCESS BY INDEX ROWID| REGISTRATION | 7 | 133 | 2406 (1)| 00:00:29 |
|* 8 | INDEX RANGE SCAN | REG_ALT | 2667 | | 9 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | PK_STUDENT | 1 | | 0 (0)| 00:00:01 |
| 10 | TABLE ACCESS BY INDEX ROWID | STUDENT | 1 | 53 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------
2/21/2013 Confidential - Internal Use Only 22
Case Study 2
• Lookup order status for caller
SELECT o.OrderID, c.LastName, p.ProductID, p.Description,
sd.ActualShipDate, sd.ShipStatus, sd.ExpectedShipDate
FROM Orders o
INNER JOIN Item i ON i.OrderID = o.OrderID
INNER JOIN Customer c ON c.CustomerID = o.CustomerID
INNER JOIN ShipmentDetails sd ON sd.ShipmentID = i.ShipmentID
INNER JOIN Product p ON p.ProductID = i.ProductID
INNER JOIN Address a ON a.AddressID = sd.AddressID
WHERE c.LastName LIKE NVL(:1,'') || '%'
AND c.FirstName LIKE NVL(:2,'') || '%'
AND o.OrderDate >= SYSDATE - 30
AND o.OrderStatus <> 'C'
• Execution Stats – 73,600 Logical Reads
2/21/2013 Confidential - Internal Use Only 23
Case Study 2
• Lookup order status for caller
SELECT o.OrderID, c.LastName, p.ProductID, p.Description,
sd.ActualShipDate, sd.ShipStatus, sd.ExpectedShipDate
FROM Orders o
INNER JOIN Item i ON i.OrderID = o.OrderID
INNER JOIN Customer c ON c.CustomerID = o.CustomerID
INNER JOIN ShipmentDetails sd ON sd.ShipmentID = i.ShipmentID
INNER JOIN Product p ON p.ProductID = i.ProductID
INNER JOIN Address a ON a.AddressID = sd.AddressID
WHERE c.LastName LIKE 'SMI%'
AND c.FirstName LIKE '%'
AND o.OrderDate >= SYSDATE - 30
AND o.OrderStatus <> 'C'
• Execution Stats – 73,600 Logical Reads
2/21/2013 Confidential - Internal Use Only 24
Database Diagram
2/21/2013 Confidential - Internal Use Only 25
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 1164 | 4892 (2)| 00:00:59 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 6 | 1164 | 4892 (2)| 00:00:59 |
| 3 | NESTED LOOPS | | 6 | 510 | 4886 (2)| 00:00:59 |
|* 4 | HASH JOIN | | 105 | 5460 | 4782 (2)| 00:00:58 |
|* 5 | HASH JOIN | | 1320 | 44880 | 4118 (2)| 00:00:50 |
|* 6 | TABLE ACCESS FULL | SHIPMENTDETAILS | 304 | 6080 | 1070 (2)| 00:00:13 |
| 7 | TABLE ACCESS FULL | ITEM | 3588K| 47M| 3036 (1)| 00:00:37 |
|* 8 | TABLE ACCESS FULL | ORDERS | 54903 | 965K| 663 (3)| 00:00:08 |
|* 9 | TABLE ACCESS BY INDEX ROWID| CUSTOMER | 1 | 33 | 1 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK_CUSTOMER | 1 | | 0 (0)| 00:00:01 |
|* 11 | INDEX UNIQUE SCAN | PK_PRODUCT | 1 | | 0 (0)| 00:00:01 |
| 12 | TABLE ACCESS BY INDEX ROWID | PRODUCT | 1 | 109 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("I"."ORDERID"="O"."ORDERID")
5 - access("SD"."SHIPMENTID"="I"."SHIPMENTID")
6 - filter("SD"."SHIPSTATUS"<>'C')
8 - filter("O"."ORDERDATE">=SYSDATE@!-30)
9 - filter("C"."LASTNAME" LIKE 'SMI%')
10 - access("C"."CUSTOMERID"="O"."CUSTOMERID")
11 - access("P"."PRODUCTID"="I"."PRODUCTID")
Execution Plan
2/21/2013 Confidential - Internal Use Only 26
SELECT COUNT(1) FROM Customer
WHERE LastName LIKE 'SMI%'
1917 / 52189 = .04
SELECT COUNT(1) FROM Orders
WHERE OrderDate >= SYSDATE - 30
55067 / 690671 = .08
SELECT COUNT(1) FROM Orders
WHERE OrderStatus <> 'C'
3760 / 690671 = .005
o .08
.04i c
psd
a
.005
SQL Diagram
2/21/2013 Confidential - Internal Use Only 27
• Only 0.5% of rows are <> ‘C’
• How about changing the query?
– AND o.OrderStatus = 'I'
• Add an Index on OrderStatus
– Collect histograms
SELECT OrderStatus, COUNT(1)
FROM Orders
GROUP BY OrderStatus
I 3760
C 686911
Data Skew Problems
2/21/2013 Confidential - Internal Use Only 28
New Execution Plan
CREATE INDEX order_status ON Orders (OrderStatus)
Execution Stats – 7,221 Logical Reads
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1581 | 301K| 3722 (1)| 00:00:45 |
|* 1 | HASH JOIN | | 1581 | 301K| 3722 (1)| 00:00:45 |
|* 2 | HASH JOIN | | 1581 | 270K| 2655 (1)| 00:00:32 |
| 3 | NESTED LOOPS | | | | | |
| 4 | NESTED LOOPS | | 1581 | 101K| 2587 (1)| 00:00:32 |
|* 5 | HASH JOIN | | 303 | 15756 | 170 (1)| 00:00:03 |
|* 6 | TABLE ACCESS BY INDEX ROWID| ORDERS | 303 | 5757 | 33 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | ORDER_STATUS | 3811 | | 9 (0)| 00:00:01 |
|* 8 | VIEW | index$_join$_001 | 2055 | 67815 | 137 (1)| 00:00:02 |
|* 9 | HASH JOIN | | | | | |
|* 10 | INDEX RANGE SCAN | CUSTOMER_LN | 2055 | 67815 | 14 (8)| 00:00:01 |
| 11 | INDEX FAST FULL SCAN | PK_CUSTOMER | 2055 | 67815 | 123 (0)| 00:00:02 |
|* 12 | INDEX RANGE SCAN | PK_ORDERINFO | 5 | | 2 (0)| 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID | ITEM | 5 | 70 | 8 (0)| 00:00:01 |
| 14 | TABLE ACCESS FULL | PRODUCT | 8914 | 948K| 68 (0)| 00:00:01 |
| 15 | TABLE ACCESS FULL | SHIPMENTDETAILS | 836K| 15M| 1064 (1)| 00:00:13 |
-----------------------------------------------------------------------------------------------------
2/21/2013 Confidential - Internal Use Only 29
• Tuning SQL gives more “bang for the buck”
• Make sure you are tuning the correct query
• Use Wait Events and Response Time Analysis
– Locking problems may not be a Query Tuning issue
– Wait events tell you where to start
• Use “Real Execution Plans”
– Get plan_hash_value from V$SESSION, V$SQL
– Pass it to V$SQL_PLAN to get Real Plan
• Ignite – Does All of Above For You
– OEM Does not Give you Enough Details
• SQL Diagramming - “Get it right the First Time”
Takeaway Points
Q&A
Thank you for attending.
More questions?
Contact Dean at
DeanRichards@confio.com
Download free trial of Ignite at
http//www.confio.com
2/21/2013 30

More Related Content

PDF
Hash join use memory optimization
PDF
Oracle statistics by example
PDF
Indexing Strategies for Oracle Databases - Beyond the Create Index Statement
PDF
Oracle Diagnostics : Joins - 1
PDF
4aa4 5484enw
TXT
Validate application accountin_140315
PPTX
Adaptive Query Optimization
PDF
Final Report
Hash join use memory optimization
Oracle statistics by example
Indexing Strategies for Oracle Databases - Beyond the Create Index Statement
Oracle Diagnostics : Joins - 1
4aa4 5484enw
Validate application accountin_140315
Adaptive Query Optimization
Final Report

Viewers also liked (14)

PPTX
Really using Oracle analytic SQL functions
PPSX
Analytic & Windowing functions in oracle
PPT
SQL- Introduction to advanced sql concepts
PPSX
Oracle Advanced SQL
PPT
Oracle database - Analytic functions - Advanced cases
PDF
The best Oracle Database 12c Tuning Features for Developers
PDF
Oracle’s Advanced Analytics & Machine Learning 12.2c New Features & Road Map;...
PDF
The Features That (maybe) You Didn't Know About
PDF
OOW2016: Exploring Advanced SQL Techniques Using Analytic Functions
PPTX
Exploring Advanced SQL Techniques Using Analytic Functions
PDF
Oracle Database Advanced Querying (2016)
PDF
Advanced PL/SQL Optimizing for Better Performance 2016
PPTX
Oracle sql analytic functions
PDF
Oracle 12c New Features For Better Performance
Really using Oracle analytic SQL functions
Analytic & Windowing functions in oracle
SQL- Introduction to advanced sql concepts
Oracle Advanced SQL
Oracle database - Analytic functions - Advanced cases
The best Oracle Database 12c Tuning Features for Developers
Oracle’s Advanced Analytics & Machine Learning 12.2c New Features & Road Map;...
The Features That (maybe) You Didn't Know About
OOW2016: Exploring Advanced SQL Techniques Using Analytic Functions
Exploring Advanced SQL Techniques Using Analytic Functions
Oracle Database Advanced Querying (2016)
Advanced PL/SQL Optimizing for Better Performance 2016
Oracle sql analytic functions
Oracle 12c New Features For Better Performance
Ad

Similar to Oracle Query Tuning Tips - Get it Right the First Time (20)

PDF
SQL Server Query Tuning Tips - Get it Right the First Time
PPTX
Top 10 tips for Oracle performance
PDF
Microsoft SQL Server Query Tuning
PPTX
Sql and PL/SQL Best Practices I
PDF
SQL Server Tuning to Improve Database Performance
PPTX
Database Performance Tuning
PPTX
Oracle sql high performance tuning
PDF
4 execution plans
PPTX
Writing efficient sql
PDF
Advanced tips for making Oracle databases faster
PDF
Brad McGehee Intepreting Execution Plans Mar09
PDF
Brad McGehee Intepreting Execution Plans Mar09
PDF
NOCOUG_201311_Fine_Tuning_Execution_Plans.pdf
PDF
On Seeing Double in V$SQL_Thomas_Kytepdf
PDF
Are you a monkey or an astronaut?
PPTX
SQL Server Deep Drive
PPT
Dbms plan - A swiss army knife for performance engineers
PDF
Hailey_Database_Performance_Made_Easy_through_Graphics.pdf
PDF
Developer day v2
PPTX
Oracle database performance tuning
SQL Server Query Tuning Tips - Get it Right the First Time
Top 10 tips for Oracle performance
Microsoft SQL Server Query Tuning
Sql and PL/SQL Best Practices I
SQL Server Tuning to Improve Database Performance
Database Performance Tuning
Oracle sql high performance tuning
4 execution plans
Writing efficient sql
Advanced tips for making Oracle databases faster
Brad McGehee Intepreting Execution Plans Mar09
Brad McGehee Intepreting Execution Plans Mar09
NOCOUG_201311_Fine_Tuning_Execution_Plans.pdf
On Seeing Double in V$SQL_Thomas_Kytepdf
Are you a monkey or an astronaut?
SQL Server Deep Drive
Dbms plan - A swiss army knife for performance engineers
Hailey_Database_Performance_Made_Easy_through_Graphics.pdf
Developer day v2
Oracle database performance tuning
Ad

Recently uploaded (20)

PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
cuic standard and advanced reporting.pdf
PDF
Machine learning based COVID-19 study performance prediction
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Encapsulation theory and applications.pdf
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Approach and Philosophy of On baking technology
PPTX
Big Data Technologies - Introduction.pptx
PPTX
Spectroscopy.pptx food analysis technology
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
DOCX
The AUB Centre for AI in Media Proposal.docx
Diabetes mellitus diagnosis method based random forest with bat algorithm
Unlocking AI with Model Context Protocol (MCP)
cuic standard and advanced reporting.pdf
Machine learning based COVID-19 study performance prediction
Review of recent advances in non-invasive hemoglobin estimation
The Rise and Fall of 3GPP – Time for a Sabbatical?
Digital-Transformation-Roadmap-for-Companies.pptx
Encapsulation theory and applications.pdf
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Programs and apps: productivity, graphics, security and other tools
Dropbox Q2 2025 Financial Results & Investor Presentation
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Understanding_Digital_Forensics_Presentation.pptx
Per capita expenditure prediction using model stacking based on satellite ima...
Approach and Philosophy of On baking technology
Big Data Technologies - Introduction.pptx
Spectroscopy.pptx food analysis technology
Mobile App Security Testing_ A Comprehensive Guide.pdf
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
The AUB Centre for AI in Media Proposal.docx

Oracle Query Tuning Tips - Get it Right the First Time

  • 1. SQL Query Tuning Tips for Oracle Get it Right the First Time Dean Richards Lead DBA, Confio Software 2/21/2013 1
  • 2. 2/21/2013 Confidential - Internal Use Only 2 Who Am I? • 20+ Years in Oracle & SQL Server – DBA and Developer – Worked for Oracle SPG • Lead DBA for Confio Software – DeanRichards@confio.com – Makers of Ignite8 Response Time Analysis Tools – http://www.ignitefree.com – only free RTA Tool • Specialize in Performance Tuning
  • 3. 2/21/2013 3 Agenda • Introduction • Which Query Should I Tune? • Query Plans • SQL Diagramming – Who registered yesterday for Tuning Class – Check order status
  • 4. 2/21/2013 Confidential - Internal Use Only 4 Why Focus on Queries • Most Applications – Read and Write data to/from database – Simple manipulation of data – Deal with smaller amounts of data • Most Databases – Examine larger amounts of data, return a little – Inefficiencies quickly become bottleneck • Why do SQL tuning? – Tuning SQL - “Gives the most bang for your buck” – Changes to SQL are Safer – ~85% of performance issues are SQL related
  • 5. 2/21/2013 Confidential - Internal Use Only 5 Who Should Tune • Developers? – Developing applications is very difficult – Typically focused on functionality – Not much time left to tune SQL – Do not get enough practice – SQL runs differently in Production than Dev/Test • DBA? – Do not know the code like developers do – Focus on “Keep the Lights On” – Very complex environment • Need a team approach – But also need someone to lead the effort
  • 6. 2/21/2013 Confidential - Internal Use Only 6 Which SQL • User / Batch Job Complaints • Queries Performing Most I/O (LIO, PIO) • Queries Consuming CPU • Queries Doing Full Table Scans • Known Poorly Performing SQL • Tracing a Session / Process • Highest Response Times (Ignite for Oracle) select sql_text, elapsed_time, cpu_time, executions, sql_id, hash_value, last_active_time, plan_hash_value, program_id, module, action from v$sql order by elapsed_time /
  • 7. 2/21/2013 Confidential - Internal Use Only 7 SQL Wait States  Understand the total time a Query spends in Database  Measure time while Query executes  SQL Server helps by providing Wait Types Focus on Response Time
  • 8. 2/21/2013 Confidential - Internal Use Only 8 Oracle Wait Interface V$SQL SQL_ID SQL_FULLTEXT V$SESSION SID USERNAME SQL_ID PROGRAM MODULE ACTION PLAN_HASH_VALUE ROW_WAIT_OBJ# V$SQLAREA SQL_ID EXECUTIONS PARSE_CALLS BUFFER_GETS DISK_READS V$SESSION_WAIT SID EVENT P1, P1RAW, P2, P2RAW, P3, P3RAW STATE (WAITING, WAITED…) • Oracle 10g added this info to V$SESSION V$SQL_PLAN SQL_ID PLAN_HASH_VALUE DBA_OBJECTS OBJECT_ID OBJECT_NAME OBJECT_TYPE
  • 9. 2/21/2013 Confidential - Internal Use Only 9 Oracle Wait Interface SELECT s.sql_id, sql.sql_text, sql.plan_hash_value, DECODE(s.state, 'WAITING', s.event, 'CPU/LogicalIO') waitevent, s.p1, s.p2, s.p3 FROM v$session s, v$sql sql WHERE s.sql_id = sql.sql_id AND s.sql_address = sql.address AND program = ‘…’ AND s.sid = … AND <whatever else you know>
  • 10. 2/21/2013 Confidential - Internal Use Only 10 SQL Plan • EXPLAIN PLAN – Estimated execution plan – Can be wrong for many reasons – What most tools show you • V$SQL_PLAN (Oracle 9i+) – Real execution plan – Use DBMS_XPLAN for display • Confio Ignite for Oracle – Gathers real plan – Shows it historically
  • 11. 2/21/2013 Confidential - Internal Use Only 11 DBMS_XPLAN select * from table ( dbms_xplan.display_cursor(‘&SQLID’,ChildNo)); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID f7jqysdfu2f2s, child number 0 ------------------------------------- update emp set hire_date = to_date(':1') where id=:2 Plan hash value: 1494045816 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | UPDATE STATEMENT | | | | 3025 (100)| | | 1 | UPDATE | EMP | | | | | |* 2 | TABLE ACCESS FULL| EMP | 122 | 2684 | 3025 (1)| 00:00:37 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("ID"=3247)
  • 12. 2/21/2013 Confidential - Internal Use Only 12 All Plans Not Equal SELECT company, attribute FROM data_out WHERE segment = :B1 • Wait Time – 100% on “db file scattered read” • Plan from EXPLAIN PLAN • Plan from V$SQL_PLAN using DBMS_XPLAN
  • 13. 2/21/2013 Confidential - Internal Use Only 13 Bind Values • V$SQL_BIND_CAPTURE – STATISTICS_LEVEL = TYPICAL or ALL – Collected at 15 minute intervals SELECT name, position, datatype_string, value_string FROM v$sql_bind_capture WHERE sql_id = '15uughacxfh13'; NAME POSITION DATATYPE_STRING VALUE_STRING ----- ---------- --------------- ------------ :B1 1 BINARY_DOUBLE 189 • Bind Values also provided by tracing – Level 4 – bind values – Level 8 – wait information – Level 12 – bind values and wait information
  • 14. 2/21/2013 Confidential - Internal Use Only 14 Case Studies • SQL Diagramming • Case Study 1 – Who registered for Tuning Class yesterday • Case Study 2 – Check order status
  • 15. 2/21/2013 Confidential - Internal Use Only 15 Case Study 1 • Who registered yesterday for SQL Tuning 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 :1 AND :2 AND r.cancelled = 'N' • Execution Stats – 12,634 Logical Reads
  • 16. 2/21/2013 Confidential - Internal Use Only 16 Database Diagram
  • 17. 2/21/2013 Confidential - Internal Use Only 17 Execution Plan ---------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 7 | 819 | 3173 (5)| 00:00:39 | |* 1 | FILTER | | | | | | | 2 | NESTED LOOPS | | | | | | | 3 | NESTED LOOPS | | 7 | 819 | 3173 (5)| 00:00:39 | |* 4 | HASH JOIN | | 7 | 448 | 3166 (5)| 00:00:38 | |* 5 | TABLE ACCESS FULL | CLASS | 1 | 45 | 22 (0)| 00:00:01 | |* 6 | TABLE ACCESS FULL | REGISTRATION | 8334 | 154K| 3144 (5)| 00:00:38 | |* 7 | INDEX UNIQUE SCAN | PK_STUDENT | 1 | | 0 (0)| 00:00:01 | | 8 | TABLE ACCESS BY INDEX ROWID| STUDENT | 1 | 53 | 1 (0)| 00:00:01 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(TRUNC(SYSDATE@!-1)<=TRUNC(SYSDATE@!)) 4 - access("R"."CLASS_ID"="C"."CLASS_ID") 5 - filter("C"."NAME"='SQL TUNING') 6 - filter("R"."SIGNUP_DATE">=TRUNC(SYSDATE@!-1) AND "R"."CANCELLED"='N' AND "R"."SIGNUP_DATE"<=TRUNC(SYSDATE@!)) 7 - access("S"."STUDENT_ID"="R"."STUDENT_ID")
  • 18. 2/21/2013 Confidential - Internal Use Only 18 SQL Diagramming registration student class 5 1 30 1 .03 .001 select count(1) from registration where cancelled = 'N' and signup_date between '2012-12-05 00:00' and '2012-12-06 00:00' 54,554 / 1,639,186 = 0.03 select count(1) from class where name = 'SQL TUNING' 2 / 1,267 = .001 • Great Book - “SQL Tuning” by Dan Tow – Teaches SQL Diagramming – http://www.singingsql.com
  • 19. 2/21/2013 Confidential - Internal Use Only 19 New Execution Plan • Execution Stats – 11,168 Logical Reads • Why does a Full Table Scan still occur on REGISTRATION? ------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 7 | 819 | 3153 (5)| 00:00:38 | |* 1 | FILTER | | | | | | | 2 | NESTED LOOPS | | | | | | | 3 | NESTED LOOPS | | 7 | 819 | 3153 (5)| 00:00:38 | |* 4 | HASH JOIN | | 7 | 448 | 3146 (5)| 00:00:38 | | 5 | TABLE ACCESS BY INDEX ROWID| CLASS | 1 | 45 | 2 (0)| 00:00:01 | |* 6 | INDEX RANGE SCAN | CL_NAME | 1 | | 1 (0)| 00:00:01 | |* 7 | TABLE ACCESS FULL | REGISTRATION | 8334 | 154K| 3144 (5)| 00:00:38 | |* 8 | INDEX UNIQUE SCAN | PK_STUDENT | 1 | | 0 (0)| 00:00:01 | | 9 | TABLE ACCESS BY INDEX ROWID | STUDENT | 1 | 53 | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------ CREATE INDEX cl_name ON class(name)
  • 20. 2/21/2013 Confidential - Internal Use Only 20 Database Diagram
  • 21. 2/21/2013 Confidential - Internal Use Only 21 New Execution Plan CREATE INDEX reg_alt ON registration(class_id) • Execution Stats – 4,831 Logical Reads ------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 7 | 819 | 2415 (1)| 00:00:29 | |* 1 | FILTER | | | | | | | 2 | NESTED LOOPS | | | | | | | 3 | NESTED LOOPS | | 7 | 819 | 2415 (1)| 00:00:29 | | 4 | NESTED LOOPS | | 7 | 448 | 2408 (1)| 00:00:29 | | 5 | TABLE ACCESS BY INDEX ROWID| CLASS | 1 | 45 | 2 (0)| 00:00:01 | |* 6 | INDEX RANGE SCAN | CL_NAME | 1 | | 1 (0)| 00:00:01 | |* 7 | TABLE ACCESS BY INDEX ROWID| REGISTRATION | 7 | 133 | 2406 (1)| 00:00:29 | |* 8 | INDEX RANGE SCAN | REG_ALT | 2667 | | 9 (0)| 00:00:01 | |* 9 | INDEX UNIQUE SCAN | PK_STUDENT | 1 | | 0 (0)| 00:00:01 | | 10 | TABLE ACCESS BY INDEX ROWID | STUDENT | 1 | 53 | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------
  • 22. 2/21/2013 Confidential - Internal Use Only 22 Case Study 2 • Lookup order status for caller SELECT o.OrderID, c.LastName, p.ProductID, p.Description, sd.ActualShipDate, sd.ShipStatus, sd.ExpectedShipDate FROM Orders o INNER JOIN Item i ON i.OrderID = o.OrderID INNER JOIN Customer c ON c.CustomerID = o.CustomerID INNER JOIN ShipmentDetails sd ON sd.ShipmentID = i.ShipmentID INNER JOIN Product p ON p.ProductID = i.ProductID INNER JOIN Address a ON a.AddressID = sd.AddressID WHERE c.LastName LIKE NVL(:1,'') || '%' AND c.FirstName LIKE NVL(:2,'') || '%' AND o.OrderDate >= SYSDATE - 30 AND o.OrderStatus <> 'C' • Execution Stats – 73,600 Logical Reads
  • 23. 2/21/2013 Confidential - Internal Use Only 23 Case Study 2 • Lookup order status for caller SELECT o.OrderID, c.LastName, p.ProductID, p.Description, sd.ActualShipDate, sd.ShipStatus, sd.ExpectedShipDate FROM Orders o INNER JOIN Item i ON i.OrderID = o.OrderID INNER JOIN Customer c ON c.CustomerID = o.CustomerID INNER JOIN ShipmentDetails sd ON sd.ShipmentID = i.ShipmentID INNER JOIN Product p ON p.ProductID = i.ProductID INNER JOIN Address a ON a.AddressID = sd.AddressID WHERE c.LastName LIKE 'SMI%' AND c.FirstName LIKE '%' AND o.OrderDate >= SYSDATE - 30 AND o.OrderStatus <> 'C' • Execution Stats – 73,600 Logical Reads
  • 24. 2/21/2013 Confidential - Internal Use Only 24 Database Diagram
  • 25. 2/21/2013 Confidential - Internal Use Only 25 -------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 6 | 1164 | 4892 (2)| 00:00:59 | | 1 | NESTED LOOPS | | | | | | | 2 | NESTED LOOPS | | 6 | 1164 | 4892 (2)| 00:00:59 | | 3 | NESTED LOOPS | | 6 | 510 | 4886 (2)| 00:00:59 | |* 4 | HASH JOIN | | 105 | 5460 | 4782 (2)| 00:00:58 | |* 5 | HASH JOIN | | 1320 | 44880 | 4118 (2)| 00:00:50 | |* 6 | TABLE ACCESS FULL | SHIPMENTDETAILS | 304 | 6080 | 1070 (2)| 00:00:13 | | 7 | TABLE ACCESS FULL | ITEM | 3588K| 47M| 3036 (1)| 00:00:37 | |* 8 | TABLE ACCESS FULL | ORDERS | 54903 | 965K| 663 (3)| 00:00:08 | |* 9 | TABLE ACCESS BY INDEX ROWID| CUSTOMER | 1 | 33 | 1 (0)| 00:00:01 | |* 10 | INDEX UNIQUE SCAN | PK_CUSTOMER | 1 | | 0 (0)| 00:00:01 | |* 11 | INDEX UNIQUE SCAN | PK_PRODUCT | 1 | | 0 (0)| 00:00:01 | | 12 | TABLE ACCESS BY INDEX ROWID | PRODUCT | 1 | 109 | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("I"."ORDERID"="O"."ORDERID") 5 - access("SD"."SHIPMENTID"="I"."SHIPMENTID") 6 - filter("SD"."SHIPSTATUS"<>'C') 8 - filter("O"."ORDERDATE">=SYSDATE@!-30) 9 - filter("C"."LASTNAME" LIKE 'SMI%') 10 - access("C"."CUSTOMERID"="O"."CUSTOMERID") 11 - access("P"."PRODUCTID"="I"."PRODUCTID") Execution Plan
  • 26. 2/21/2013 Confidential - Internal Use Only 26 SELECT COUNT(1) FROM Customer WHERE LastName LIKE 'SMI%' 1917 / 52189 = .04 SELECT COUNT(1) FROM Orders WHERE OrderDate >= SYSDATE - 30 55067 / 690671 = .08 SELECT COUNT(1) FROM Orders WHERE OrderStatus <> 'C' 3760 / 690671 = .005 o .08 .04i c psd a .005 SQL Diagram
  • 27. 2/21/2013 Confidential - Internal Use Only 27 • Only 0.5% of rows are <> ‘C’ • How about changing the query? – AND o.OrderStatus = 'I' • Add an Index on OrderStatus – Collect histograms SELECT OrderStatus, COUNT(1) FROM Orders GROUP BY OrderStatus I 3760 C 686911 Data Skew Problems
  • 28. 2/21/2013 Confidential - Internal Use Only 28 New Execution Plan CREATE INDEX order_status ON Orders (OrderStatus) Execution Stats – 7,221 Logical Reads ----------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1581 | 301K| 3722 (1)| 00:00:45 | |* 1 | HASH JOIN | | 1581 | 301K| 3722 (1)| 00:00:45 | |* 2 | HASH JOIN | | 1581 | 270K| 2655 (1)| 00:00:32 | | 3 | NESTED LOOPS | | | | | | | 4 | NESTED LOOPS | | 1581 | 101K| 2587 (1)| 00:00:32 | |* 5 | HASH JOIN | | 303 | 15756 | 170 (1)| 00:00:03 | |* 6 | TABLE ACCESS BY INDEX ROWID| ORDERS | 303 | 5757 | 33 (0)| 00:00:01 | |* 7 | INDEX RANGE SCAN | ORDER_STATUS | 3811 | | 9 (0)| 00:00:01 | |* 8 | VIEW | index$_join$_001 | 2055 | 67815 | 137 (1)| 00:00:02 | |* 9 | HASH JOIN | | | | | | |* 10 | INDEX RANGE SCAN | CUSTOMER_LN | 2055 | 67815 | 14 (8)| 00:00:01 | | 11 | INDEX FAST FULL SCAN | PK_CUSTOMER | 2055 | 67815 | 123 (0)| 00:00:02 | |* 12 | INDEX RANGE SCAN | PK_ORDERINFO | 5 | | 2 (0)| 00:00:01 | | 13 | TABLE ACCESS BY INDEX ROWID | ITEM | 5 | 70 | 8 (0)| 00:00:01 | | 14 | TABLE ACCESS FULL | PRODUCT | 8914 | 948K| 68 (0)| 00:00:01 | | 15 | TABLE ACCESS FULL | SHIPMENTDETAILS | 836K| 15M| 1064 (1)| 00:00:13 | -----------------------------------------------------------------------------------------------------
  • 29. 2/21/2013 Confidential - Internal Use Only 29 • Tuning SQL gives more “bang for the buck” • Make sure you are tuning the correct query • Use Wait Events and Response Time Analysis – Locking problems may not be a Query Tuning issue – Wait events tell you where to start • Use “Real Execution Plans” – Get plan_hash_value from V$SESSION, V$SQL – Pass it to V$SQL_PLAN to get Real Plan • Ignite – Does All of Above For You – OEM Does not Give you Enough Details • SQL Diagramming - “Get it right the First Time” Takeaway Points
  • 30. Q&A Thank you for attending. More questions? Contact Dean at DeanRichards@confio.com Download free trial of Ignite at http//www.confio.com 2/21/2013 30