I had a colleague ask to help with tuning a massive query. I have been tuning SQL for several years now and the process is quite different from 5 or 10 years ago. At one time, I knew a consultant that was all he did (now that is specialized). Back in the days of Oracle 8 and earlier, tuning tips were introduced and usually involved overriding the CBO (Cost Based Optimizer). The rule optimizer hint was done away with 10g. Consequently, the black art of tuning is not as important as it once was. I work primarily on the package Oracle Apps and touching base queries is verboten.
However, the query in question is for a custom export so I was able to discover and use the new 10g SQL Tuning Advisor. I went through the process described below but we decided to re-structure the query. Many times, I have found that a query is so complex that a de-normalizing ETL process based around a PL/SQL cursor and package is preferable to a multi-UNION query.
I do like the new SQL Advisor and I am filing this away in my toolbox. I believe there is a graphical front end to the process via Enterprise Manager. Unfortunately, we are having some difficulties with Enterprise Manager Agents and Windows.
The following diagram is from an Oracle site:
One of the first things I did is to make sure that APPS had appropriate permissions:
GRANT ADVISOR TO APPS;
GRANT SELECT_CATALOG_ROLE TO APPS;
GRANT EXECUTE ON DBMS_SQLTUNE TO APPS;
Create the Tuning Task:
DECLARE
MT_SQL_TUNE2 VARCHAR2(30);
my_sqltext CLOB;
BEGIN
my_sqltext := 'select po_headers_all.segment1,
po_lines_all.line_num,
pov.segment1,
pov.vendor_name,
REPLACE(REPLACE(po_lines_all.item_description, (CHR(10))), CHR(13)),
po_headers_all.note_to_receiver,
po_headers_all.approved_date,
NVL(po_lines_all.quantity, 0),
DECODE(po_lines_all.cancel_flag, ''Y'', po_lines_all.quantity, NULL),
po_lines_all.vendor_product_num,
po_lines_all.unit_meas_lookup_code,
it.segment1,
po_lines_all.unit_price….
MT_SQL_TUNE2 := DBMS_SQLTUNE.CREATE_TUNING_TASK(
sql_text => my_sqltext,
user_name => 'APPS',
scope => 'COMPREHENSIVE',
time_limit => 60,
task_name => 'APPS_TEST_sql_tuning_task',
description => 'Tuning Task for PO');
END;
Execute the Tuning Task
The task can be executed by:
execute dbms_sqltune.Execute_tuning_task (task_name => 'APPS_TEST_sql_tuning_task');
Note the task name needs to be changed each time. This is the longest part of the process as the SQL query is executed. I used the following query to track the progress:
SELECT * FROM DBA_ADVISOR_LOG where task_name = 'APPS_TEST_sql_tuning_task'
Report the Tuning Task
From a SQL Plus editor or session, set the following:
SQL> set long 65536
SQL> set linesize 100
Next, execute the following query:
select dbms_sqltune.report_tuning_task('APPS_TEST_sql_tuning_task') from dual;
The output from the query should look something like this:
DBMS_SQLTUNE.REPORT_TUNING_TAS
--------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name : APPS_TEST_sql_tuning_task10
Tuning Task Owner : SYSTEM
Scope : COMPREHENSIVE
Time Limit(seconds) : 60
Completion Status : COMPLETED
Started at : 04/05/2011 14:36:30
Completed at : 04/05/2011 14:36:31
Number of SQL Profile Findings : 1
-------------------------------------------------------------------------------
Schema Name: APPS
SQL ID : 4pwu14mywuc05
SQL Text : select po_headers_all.segment1,
po_lines_all.line_num,
pov.segment1,
pov.vendor_name,
REPLACE(REPLACE(po_lines_all.item_description,
…..
-------------------------------------------------------------------------------
FINDINGS SECTION (1 finding)
-------------------------------------------------------------------------------
1- SQL Profile Finding (see explain plans section below)
--------------------------------------------------------
A potentially better execution plan was found for this statement.
Recommendation (estimated benefit<=10%)
---------------------------------------
- Consider accepting the recommended SQL profile.
execute dbms_sqltune.accept_sql_profile(task_name =>
'APPS_TEST_sql_tuning_task10', replace => TRUE);
-------------------------------------------------------------------------------
EXPLAIN PLANS SECTION
-------------------------------------------------------------------------------
1- Original With Adjusted Cost
------------------------------
Plan hash value: 746338343
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2164 | 807K
| 1 | NESTED LOOPS OUTER | | 2164 | 807K
| 2 | NESTED LOOPS | | 2164 | 781K
| 3 | NESTED LOOPS | | 734 | 212K
The main area to review is the Findings Section. In this case, an alternative plan has been suggested.
Implement Recommendations
execute dbms_sqltune.accept_sql_profile(task_name => 'APPS_TEST_sql_tuning_task', replace => TRUE);
I used a couple of other commands to control the process:
This command will cancel a long running tuning task
EXECUTE DBMS_ADVISOR.CANCEL_TASK('APPS_TEST_sql_tuning_task');
Another valuable command to delete a tuning task is:
EXECUTE DBMS_ADVISOR.DELETE_TASK('APPS_TEST_sql_tuning_task');
I found that If you don't clean out the task from the DBA_ADVISOR_LOG, you will need to define a new task and start the process all over again.