SQL調優工具包DBMS_SQLTUNE的使用方法

oracle 提供了優化建議功能包DBMS_SQLTUNE,該包可以幫助我們分析SQL,並提供優化建議。

Sql_Profile是用來影響數據庫執行計劃生成的一組信息文件的集合,可以在不改變原有SQL語句的前提下,達到類似HINTS改變其執行計劃的目的。


原有執行計劃

alter session set statistics_level=all;
set serveroutput off
select * from test.emp where ename='SCOTT' and DEPTNO=20;
SELECT * FROM table(dbms_xplan.display_cursor(NULL,NULL,'runstats_last'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID  8k1gbrapm7zpd, child number 0
-------------------------------------
select * from test.emp where ename='SCOTT' and DEPTNO=20
Plan hash value: 3956160932
------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |      1 |00:00:00.01 |       4 |
|*  1 |  TABLE ACCESS FULL| EMP  |      1 |      1 |      1 |00:00:00.01 |       4 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(("ENAME"='SCOTT' AND "DEPTNO"=20))




下面就用DBMS_SQLTUNE優化該SQL
--1.賦予用戶ADVISOR權限

grant ADVISOR  to test;



--2.創建sql tuning任務

conn test/test
DECLARE
 my_task_name VARCHAR2(30);
 my_sqltext   CLOB;
BEGIN
 my_sqltext := 'select * from emp where ename= :name and DEPTNO= :deptno';
 my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(
         sql_text    => my_sqltext,
              bind_list    => sql_binds(anydata.convertvarchar2(10),anydata.convertnumber(2)), 
         user_name    => 'TEST',
         scope      => 'COMPREHENSIVE',
         time_limit   => 60,
         task_name    => 'test_sql_tuning', 
         description   => 'Task to tune a query on emp');
END;
/

注意:

記住,DBMS_SQLTUNE.CREATE_TUNING_TASK是一個函數,必須要有返回值。
上面在定義了一個TASK後,可通過DBMS_SQLTUNE.EXECUTE_TUNING_TASK來執行此調優過程。


參數說明:
bind_list:

多個綁定變量以','逗號分隔。參數值一定要根據綁定變量對應的列的類型書寫.
如:emp.ename類型是VARCHAR2(10),那麼就要寫成
bind_list    =>sql_binds(anydata.convertvarchar2(10)),

time_limit:

執行的最長時間,默認是60。


scope:
LIMITED,用大概1秒時間去優化SQL語句,但是並不進行SQL Profiling分析。
COMPREHENSIVE,進行全面分析,包含SQL Profiling分析;比LIMITED用時更長。


**也可以用sql_id創建sql tunning任務,比用sql_text方便很多

FUNCTION CREATE_TUNING_TASK RETURNS VARCHAR2
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 SQL_ID                         VARCHAR2                IN
 PLAN_HASH_VALUE                NUMBER                  IN     DEFAULT
 SCOPE                          VARCHAR2                IN     DEFAULT
 TIME_LIMIT                     NUMBER                  IN     DEFAULT
 TASK_NAME                      VARCHAR2                IN     DEFAULT
 DESCRIPTION                    VARCHAR2                IN     DEFAULT
DECLARE
 my_task_name VARCHAR2(30);
BEGIN
  my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(
         SQL_ID      => 'ddw7j6yfnw0vz',
         scope       => 'COMPREHENSIVE',  ----------->任務類型,有limited和comprehensive兩種
         time_limit  => 60,  ----------->此任務最長的執行時間
         task_name   => 'tunning_task_ddw7j6yfnw0vz', ----------->任務名
         description => 'Task to tune a query on  ddw7j6yfnw0vz' ----------->任務描述
         );
END;
/


--3.查看任務名 SELECT TASK_NAME 
FROM   DBA_ADVISOR_LOG 
WHERE  OWNER = 'TEST';
TASK_NAME
------------------------------
test_sql_tuning

--4.執行sql tuning任務

BEGIN  DBMS_SQLTUNE.EXECUTE_TUNING_TASK( task_name => 'test_sql_tuning', ------------>任務名
                                    execution_name => NULL, ----------->執行時的名稱,可爲空
                                     execution_params  => NULL,  ------------>執行參數,默認可爲空
                                    execution_desc => NULL   ------------>執行描述
);END;/



--5.查看sql tunning任務狀態

SELECT status 
FROM   USER_ADVISOR_TASKS 
WHERE  task_name = 'test_sql_tuning';
STATUS
-----------
COMPLETED



--6.展示sql tunning結果

SET LONG 10000
SET LONGCHUNKSIZE 1000
SET LINESIZE 100
SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK('test_sql_tuning')
FROM   DUAL;


DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_SQL_TUNING')
----------------------------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name   : test_sql_tuning
Tuning Task Owner  : TEST
Workload Type      : Single SQL Statement
Scope              : COMPREHENSIVE
Time Limit(seconds): 60
Completion Status  : COMPLETED
Started at         : 04/01/2014 16:45:16
Completed at       : 04/01/2014 16:45:17
DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_SQL_TUNING')
----------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Schema Name: TEST
SQL ID     : 95fv6dbj64d0f
SQL Text   : select * from emp where ename= :name and DEPTNO= :deptno
-------------------------------------------------------------------------------
FINDINGS SECTION (2 findings)
-------------------------------------------------------------------------------
1- Statistics Finding
---------------------
DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_SQL_TUNING')
----------------------------------------------------------------------------------------------------
  Table "TEST"."EMP" was not analyzed.
  Recommendation
  --------------
  - Consider collecting optimizer statistics for this table.
    execute dbms_stats.gather_table_stats(ownname => 'TEST', tabname =>
            'EMP', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
            method_opt => 'FOR ALL COLUMNS SIZE AUTO');
  Rationale
  ---------
DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_SQL_TUNING')
----------------------------------------------------------------------------------------------------
    The optimizer requires up-to-date statistics for the table in order to
    select a good execution plan.
2- Index Finding (see explain plans section below)
--------------------------------------------------
  The execution plan of this statement can be improved by creating one or more
  indices.
  Recommendation (estimated benefit: 66.67%)
  ------------------------------------------
  - Consider running the Access Advisor to improve the physical schema design
DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_SQL_TUNING')
----------------------------------------------------------------------------------------------------
    or creating the recommended index.
    create index TEST.IDX$$_00D80001 on TEST.EMP("ENAME","DEPTNO");
  Rationale
  ---------
    Creating the recommended indices significantly improves the execution plan
    of this statement. However, it might be preferable to run "Access Advisor"
    using a representative SQL workload as opposed to a single statement. This
    will allow to get comprehensive index recommendations which takes into
    account index maintenance overhead and additional space consumption.
DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_SQL_TUNING')
----------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------
EXPLAIN PLANS SECTION
-------------------------------------------------------------------------------
1- Original
-----------
Plan hash value: 3956160932
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_SQL_TUNING')
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    87 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMP  |     1 |    87 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("ENAME"=:NAME AND "DEPTNO"=:DEPTNO)
2- Using New Indices
--------------------
DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_SQL_TUNING')
----------------------------------------------------------------------------------------------------
Plan hash value: 2106247215
----------------------------------------------------------------------------------------------
| Id  | Operation                   | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                |     1 |    87 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMP            |     1 |    87 |     1   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX$$_00D80001 |     1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_SQL_TUNING')
----------------------------------------------------------------------------------------------------
---------------------------------------------------
   2 - access("ENAME"=:NAME AND "DEPTNO"=:DEPTNO)
-------------------------------------------------------------------------------
建議報告總結:
<1>收集EMP表的統計信息
execute dbms_stats.gather_table_stats(ownname => 'TEST', tabname =>'EMP', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,method_opt => 'FOR ALL COLUMNS SIZE AUTO');
<2>創建索引
create index TEST.IDX$$_00D80001 on TEST.EMP("ENAME","DEPTNO"); 
優化後執行計劃
--------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                |      1 |        |      1 |00:00:00.01 |       3 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMP            |      1 |      1 |      1 |00:00:00.01 |       3 |
|*  2 |   INDEX RANGE SCAN          | IDX$$_00D80001 |      1 |      1 |      1 |00:00:00.01 |       2 |
--------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ENAME"='SCOTT' AND "DEPTNO"=20)


ACCEPT_SQL_PROFILE                               #接受及應用一個SQL_PROFILE執行計劃給某條SQL

DBMS_SQLTUNE.ACCEPT_SQL_PROFILE (
   task_name    IN  VARCHAR2,                  -------------->執行優化的任務名
   object_id    IN  NUMBER   := NULL,           -------------->對象編號,一般不填
   name         IN  VARCHAR2 := NULL,          -------------->制定的sql_profile名稱,如果不填則由系統指派
   description  IN  VARCHAR2 := NULL,             -------------->該執行計劃的描述信息 
   category     IN  VARCHAR2 := NULL);           ------------->需要與該SESSION的sqltune_category參數相匹配
   task_owner   IN VARCHAR2  := NULL,             ------------->任務的所有者
   replace      IN BOOLEAN   := FALSE,          ------------->如果此sql_profile已存在,則決定是否替換,默認值爲不替換
   force_match  IN BOOLEAN   := FALSE,            ------------->是否強制匹配此執行計劃與所有HASH值相同的SQL,類似CURSOR_SHARING參數的FORCE
   profile_type IN VARCHAR2  := REGULAR_PROFILE);        ------------->sql_profile的類型,默認爲REGULAR_PROFILE,可修改爲PX_PROFILE,表示此執行計劃變更爲並行執行

DROP_SQL_PROFILE  
DBMS_SQLTUNE.DROP_SQL_PROFILE ( #刪除一個SQL_PROFILE的應用,讓系統自動選擇 
   name  IN  VARCHAR2,
   ignore IN  BOOLEAN  := FALSE);




--7.完成後刪除sql tunning任務

EXEC DBMS_SQLTUNE.DROP_TUNING_TASK('test_sql_tuning');



--8.其他

--sql tunning任務創建後,也可以修改參數
BEGIN
  DBMS_SQLTUNE.SET_TUNING_TASK_PARAMETER(
    task_name => 'test_sql_tuning',
    parameter => 'TIME_LIMIT', value => 300);
END;
/
--查看SQL Tuning Advisor的進展(task執行很久)
col opname for a20
col ADVISOR_NAME for a20
SELECT SID,SERIAL#,USERNAME,OPNAME,ADVISOR_NAME,TARGET_DESC,START_TIME SOFAR, TOTALWORK 
FROM   V$ADVISOR_PROGRESS 
WHERE  USERNAME = 'TEST';


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章