Oracle Performance Tuning 101 - Developer Perspective 090528 - 2
Oracle Performance Tuning 101 - Developer Perspective 090528 - 2
Tuning 101
Developer Perspective
Day 2
071024 © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 1
Agenda
Performance Tuning
Common Performance Problems (day 1)
Diagnostic Tools (day 1)
How to Identify SQL Performance Issues (day 1)
Best Practice
SQL Statements (day 2)
Schema Objects (day 3)
PL/SQL Logic (day 3)
Data Warehouse/OLTP (day 3)
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 2
Best Practices
SQL Language
Database Objects
PL/SQL
Data Warehouse/OLTP
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 3
SELECT Clause
Are you selecting more columns than needed?
Can the number of function calls be reduced or
removed?
Can the number of procedure calls be reduced or
removed?
Is the DISTINCT keyword needed?
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 4
FROM Clause
Table contains the most selective filtering condition
should be placed first, then the next selective
table…
Divide and Conquer - Use inline view to quickly
eliminate rows from a large table
Move CONNECT BY table to an inline view (dynamic
FROM table)
Hugh performance gain for a multi tables complex SQL
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 5
Divide and Conquer - Use INLINE View
SELECT…
FROM employees emp, AND chg_info.employee_id = deptc.modified_by
employees mgr, AND chg_info.status = 'A'
job_titles jobt, AND rel.node_id = sn.node_id
employee_changes deptc,
AND sn.version_id = (SELECT MAX (version_id)
employees chg_info,
FROM strct_nodes
departments newdept,
WHERE node_id = sn.node_id)
strct_nodes sn,
node_rel rel, AND rel.node_id IN (
status stat SELECT a.node_id
WHERE emp.employee_id_reports_to = mgr.employee_id FROM strct_nodes a
AND emp.status = 'A' WHERE a.version_id = sn.version_id
AND emp.job_title = jobt.job_title_id AND a.date_override IS NULL
AND emp.employee_id = deptc.employee_id START WITH a.node_id = 200000401
AND deptc.new_department_id = newdept.dept_id CONNECT BY a.parent_structure_node_id =
AND deptc.change_type = 'DEPT' PRIOR a.structure_node_id)
AND deptc.change_sequence_number = AND rel.obsolete = 'N'
(SELECT MAX (change_sequence_number) AND rel.status_id = stat.status_id
FROM employee_changes emp2 AND stat.status_name != 'INACTIVE'
WHERE change_type = 'DEPT' AND rel.employee_id = emp.employee_id
AND emp2.employee_id = deptc.employee_id)
Elapsed: 00:53:45.05
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 6
Divide and Conquer - Use INLINE View..
SELECT …
AND deptc.change_sequence_number =
FROM EMPLOYEES emp,
(SELECT MAX(change_sequence_number)
EMPLOYEES mgr, FROM
JOB_TITLES jobt , EMPLOYEE_CHANGES emp2
EMPLOYEE_CHANGES deptc, WHERE change_type = 'DEPT'
EMPLOYEES chg_info,
AND emp2.employee_id = deptc.employee_id)
DEPARTMENTS newdept ,
AND chg_info.employee_id = deptc.modified_by
( SELECT a.node_id, a.version_id
AND chg_info.status = 'A'
FROM strct_nodes a
AND rel.node_id = sn.node_id
WHERE a.date_override IS NULL
AND sn.version_id =
START WITH a.node_id = 200000401
(SELECT MAX(version_id)
CONNECT BY a.parent_structure_node_id =
FROM STRCT_NODES
PRIOR a.structure_node_id
WHERE node_id = sn.node_id)
)sn,
AND rel.obsolete = 'N'
SHR_NODE_REL rel,
AND rel.status_id = stat.status_id
SHR_STATUS stat
AND stat.status_name != 'INACTIVE'
WHERE
AND rel.employee_id = emp.employee_id
emp.employee_id_reports_to =
mgr.employee_id
AND emp.status = 'A'
AND emp.job_title = jobt.job_title_id Elapsed: 00:00:34.00
AND emp.employee_id = deptc.employee_id
AND deptc.new_department_id
=newdept.dept_id
AND deptc.change_type = 'DEPT'
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 7
WHERE Clause
Avoid implicit datatype conversion
Avoid using function on an indexed column
Avoid comparing column value with NULL
Outer Join
Use OR carefully
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 8
Datatype Conversion
A full table scan is performed on a driving table. Why?
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 9
Datatype Conversion…
Analysis
c.customer_number is defined as VARCHAR2(50)
A PK index is defined on this column
Conclusion
Change the filtering condition to
c.customer_number = ’12345’
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 10
Left-hand side column function
When comparing date value
Instead of:
TRUNC(expected_date) > TRUNC(SYSDATE)
Convert to:
Expected_date >= TRUNC(SYSDATE)+1
Instead of:
TRUNC(transaction_date) = TRUNC(SYSDATE)
Convert to:
transaction_date >= TRUNC(SYSDATE) AND
transaction_date < TRUNC(SYSDATE) + 1
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 11
Compare column value with NULL
When comparing a column value with NULL, such as:
WHERE Column_name IS NULL
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 12
Using NVL() function
Instead of using NVL() on a column:
WHERE NVL(region, :input_region) = :input_region
Change to
…
WHERE region = :input_region
UNION ALL
…
WHERE region IS NULL
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 13
Use Outer Join Carefully
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 14
IN VS. EXISTS
Use IN if the sub-query is more selective
Use EXISTS if the sub-query is less selective
Always use NOT EXISTS instead of NOT IN
NOT EXISTS will return rows with NULL value
NOT IN will NOT return rows with NULL value
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 15
Use OR Operator Carefully
The following SQL statement returns in 43 minutes.
MIC table contains 40 million rows
HTS table contains 85 rows
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 16
Use OR Operator Carefully…
Analysis
Most selective filter is on ges_update_date column that is
part of the OR condition
Index is defined. However Oracle choose not to use this
index
Conclusion
Break the SQL statement into 2 SELECTs and joined with a
UNION ALL
SELECT … FROM … WHERE …
mic.ges_update_date > sysdate-10
AND
UNION ALL
SELECT … FROM … WHERE …
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 17
UNION ALL
Use UNION ALL whenever possible (no implicit sorts)
UNION will sort the result set for each SELECT before
combining the final result set
Remove DISTINCT keyword from SELECT if UNION is
used
How many rows are returned from the final result set?
Can Oracle memory handle the final result set?
A 6-way UNION statement was taking 860 minutes to complete.
After:
Breaking the statement into 3 UNION ALL statements
Creating 3 Global Temporary Tables (GTTs) to store the intermediate results
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 18
Large SQL and Oracle Memory
The larger the SQL statement, the more Oracle
shareable memory allocation (cursor cache and latch
gets)
Large SQL poses scalability problem
Shared pool operations are also more expensive in a
RAC environment due to the need to acquire global
cache locks
SQL statements should not exceed 1 MB in terms of
the amount of sharable memory required:
SELECT sharable_mem, sql_text
FROM v$sql
WHERE sharable_mem > 1000000
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 19
Update Table
Update is a very expensive operation
The best Update is NO UPDATE
Instead of updating millions of rows, do this:
INSERT INTO new_table AS
SELECT <do the update here>
FROM old_table
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 20
Delete all rows from a table
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 21
Presentation_ID © 2006 Cisco Systems, Inc. All rights reserved. Cisco Confidential 22