SQL Tuning Advisor(STA) 到底做了什么?

来源:互联网 发布:质量控制系统 php 编辑:程序博客网 时间:2024/04/29 18:55
SQL Tuing Advisor(STA) 是Automatic Tuning Optimizer(自动优化调整器)的一部分。在前面的文章使用SQL tuning advisor(STA)自动优化SQL中描述了SQL Tuing Advisor(STA)的相关背景并给出示例。本文主要是描述STA底层到底为我们作了什么使得SQL语句得以优化,同时演示绑定变量的情形下接受sql profile后,后续SQL是否采纳对应的sql profile的执行计划的情形。最后给出了awr中的SQL通过STA tuning的脚本。

 

1、使用STA优化library cache中的SQL

[sql] view plaincopyprint?
  1. --演示环境  
  2. hr@CNMMBO> select * from v$version where rownum<2;  
  3.   
  4. BANNER  
  5. ----------------------------------------------------------------  
  6. Oracle Database 10g Release 10.2.0.3.0 - 64bit Production  
  7.   
  8. --下面直接根据sql_id优化library cache中的SQL语句  
  9. hr@CNMMBO> @tune_cache_sql  
  10. Enter value for input_sql_id: 8rnmr2dpnjvk8  
  11. Enter value for input_task_name: hr_query  
  12.   
  13. RECS  
  14. ---------------------------------------------------------------------------------------  
  15. GENERAL INFORMATION SECTION  
  16. -------------------------------------------------------------------------------  
  17. Tuning Task Name                  : hr_query  
  18. Tuning Task Owner                 : HR  
  19. Scope                             : COMPREHENSIVE  
  20. Time Limit(seconds)               : 1800  
  21. Completion Status                 : COMPLETED  
  22. Started at                        : 06/07/2013 11:40:27  
  23. Completed at                      : 06/07/2013 11:40:28  
  24. Number of SQL Profile Findings    : 1  
  25. Number of SQL Restructure Findings: 1  
  26.   
  27. -------------------------------------------------------------------------------  
  28. Schema Name: HR  
  29. SQL ID     : 8rnmr2dpnjvk8  
  30. SQL Text   : SELECT       /*+ ORDERED */  
  31.                    *  
  32.                FROM employees e, locations l, departments d  
  33.               WHERE e.department_id = d.department_id AND l.location_id =  
  34.              d.location_id AND e.employee_id < :bnd  
  35.   
  36. -------------------------------------------------------------------------------  
  37. FINDINGS SECTION (2 findings)  
  38. -------------------------------------------------------------------------------  
  39.   
  40. 1- SQL Profile Finding (see explain plans section below)  
  41. --------------------------------------------------------  
  42.   A potentially better execution plan was found for this statement.  
  43.   
  44.   Recommendation (estimated benefit: 90.74%)  
  45.   ------------------------------------------  
  46.   - Consider accepting the recommended SQL profile.  
  47.     execute dbms_sqltune.accept_sql_profile(task_name => 'hr_query'replace  
  48.             => TRUE);  
  49.   
  50. 2- Restructure SQL finding (see plan 1 in explain plans section)  
  51. ----------------------------------------------------------------  
  52.   An expensive cartesian product operation was found at line ID 3 of the  
  53.   execution plan.  
  54.   
  55.   Recommendation  
  56.   --------------  
  57.   - Consider removing the "ORDERED" hint.  
  58.   
  59.   Rationale  
  60.   ---------  
  61.     The "ORDERED" hint might force the optimizer to generate a cartesian  
  62.     product. A cartesian product should be avoided whenever possible because  
  63.     it is an expensive operation and might produce a large amount of data.  
  64.   
  65. -------------------------------------------------------------------------------  
  66. EXPLAIN PLANS SECTION  
  67. -------------------------------------------------------------------------------  
  68.   
  69. 1- Original With Adjusted Cost  
  70. ------------------------------  
  71. Plan hash value: 3871948714  
  72.   
  73. -----------------------------------------------------------------------------------------------  
  74. | Id  | Operation                     | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
  75. -----------------------------------------------------------------------------------------------  
  76. |   0 | SELECT STATEMENT              |               |    85 | 11645 |   103   (1)| 00:00:02 |  
  77. |*  1 |  HASH JOIN                    |               |    85 | 11645 |   103   (1)| 00:00:02 |  
  78. |   2 |   TABLE ACCESS FULL           | DEPARTMENTS   |    27 |   540 |     3   (0)| 00:00:01 |  
  79. |   3 |   MERGE JOIN CARTESIAN        |               |  1973 |   225K|    99   (0)| 00:00:02 |  
  80. |   4 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |    86 |  5848 |     3   (0)| 00:00:01 |  
  81. |*  5 |     INDEX RANGE SCAN          | EMP_EMP_ID_PK |    86 |       |     1   (0)| 00:00:01 |  
  82. |   6 |    BUFFER SORT                |               |    23 |  1127 |    96   (0)| 00:00:02 |  
  83. |   7 |     TABLE ACCESS FULL         | LOCATIONS     |    23 |  1127 |     1   (0)| 00:00:01 |  
  84. -----------------------------------------------------------------------------------------------  
  85.   
  86. Predicate Information (identified by operation id):  
  87. ---------------------------------------------------  
  88.   
  89.    1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID" AND  
  90.               "L"."LOCATION_ID"="D"."LOCATION_ID")  
  91.    5 - access("E"."EMPLOYEE_ID"<:BND)  
  92.   
  93. 2- Using SQL Profile  
  94. --------------------  
  95. Plan hash value: 2153960720  
  96.   
  97. --------------------------------------------------------------------------------------------------  
  98. | Id  | Operation                     | Name             | Rows  | Bytes | Cost (%CPU)| Time     |  
  99. --------------------------------------------------------------------------------------------------  
  100. |   0 | SELECT STATEMENT              |                  |    85 | 11645 |    10  (20)| 00:00:01 |  
  101. |*  1 |  HASH JOIN                    |                  |    85 | 11645 |    10  (20)| 00:00:01 |  
  102. |   2 |   MERGE JOIN                  |                  |    27 |  1863 |     6  (17)| 00:00:01 |  
  103. |   3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS      |    27 |   540 |     2   (0)| 00:00:01 |  
  104. |   4 |     INDEX FULL SCAN           | DEPT_LOCATION_IX |    27 |       |     1   (0)| 00:00:01 |  
  105. |*  5 |    SORT JOIN                  |                  |    23 |  1127 |     4  (25)| 00:00:01 |  
  106. |   6 |     TABLE ACCESS FULL         | LOCATIONS        |    23 |  1127 |     3   (0)| 00:00:01 |  
  107. |   7 |   TABLE ACCESS BY INDEX ROWID | EMPLOYEES        |    86 |  5848 |     3   (0)| 00:00:01 |  
  108. |*  8 |    INDEX RANGE SCAN           | EMP_EMP_ID_PK    |    86 |       |     1   (0)| 00:00:01 |  
  109. --------------------------------------------------------------------------------------------------  
  110.   
  111. Predicate Information (identified by operation id):  
  112. ---------------------------------------------------  
  113.   
  114.    1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")  
  115.    5 - access("L"."LOCATION_ID"="D"."LOCATION_ID")  
  116.        filter("L"."LOCATION_ID"="D"."LOCATION_ID")  
  117.    8 - access("E"."EMPLOYEE_ID"<:BND)  
  118.   
  119. -------------------------------------------------------------------------------  
  120. -->上面的advisor report中得到了两个findings,一个是建议我们接受profile,一个建议我们移出ordered hint,因为它导致了笛卡尔集  

2、根据优化建议接受SQL profile

[sql] view plaincopyprint?
  1. -->根据上面的advisor,接下来我们accept这个profile,唯一不同的增加了一个名字,如果不指定名字,系统会自动生成一个  
  2. hr@CNMMBO> execute dbms_sqltune.accept_sql_profile(task_name => 'hr_query',replace=> TRUE,name=>'hr_profile');  
  3.   
  4. PL/SQL procedure successfully completed.  
  5.   
  6. --所有生成的SQL profile的相关信息都存放在数据字典dba_sql_profiles中  
  7. hr@CNMMBO> select name,category,signature,sql_text,created,type,status,force_matching from dba_sql_profiles;  
  8.   
  9. NAME         CATEGORY              SIGNATURE SQL_TEXT                            CREATED           TYPE      STATUS   FOR  
  10. ------------ ---------- -------------------- ----------------------------------- ----------------- --------- -------- ---  
  11. hr_profile   DEFAULT     8856746596263812636 SELECT       /*+ ORDERED */         20130607 14:27:33 MANUAL    ENABLED  NO  
  12.                                                    *  
  13.                                                FROM employees e, locations l, de  
  14.                                              partments d  
  15.                                               WHERE e.department_id = d.departme  
  16.                                              nt_id AND l.location_id = d.locatio  
  17.                                              n_id AND e.employee_id < :bnd  
  18.   
  19. ------------------------------------------------------------------------------------------------------------  
  20. --下面是dba_sql_profiles数据字典中的列几个重要的说明  
  21. a、CATEGORY: Category of the SQL profile   
  22. --  用于对SQL Profile实施分类管理,指明了当前的SQL profile属于哪一个分类,缺省情况下dafault类会被激活  
  23. --  可以在接受SQL profile时指定分类,具体参考包dbms_sqltune.accept_sql_profile  
  24. --  初始化参数sqltune_category用于控制系统和会话级别的category被激活,也就是说单个session仅仅支持单一的category激活  
  25. --  如下查看当前设定的category及如何修改     
  26. -->查看系统的sqltune_category参数  
  27. hr@CNMMBO> show parameter sqltune  
  28.   
  29. NAME                                 TYPE        VALUE  
  30. ------------------------------------ ----------- ------------------------------  
  31. sqltune_category                     string      DEFAULT  
  32.   
  33. -->通过下面的方式来修改缺省的catagory类别  
  34. alter session | system sqltune_category = category_name;  
  35.   
  36. -------------------------------------------------------------------------------------------------------------------  
  37. b、SIGNATURE: Unique identifier generated from normalized SQL text   
  38. --  用于控制标准化SQL文本的到唯一签名ID并将该ID的profile的信息存储到数据字典  
  39. --  在category激活以及profile被启用的情形下,后续的SQL语句运行时如果得到的签名ID与存储到数据字典的ID相同,则SQL profile被使用  
  40.   
  41. -------------------------------------------------------------------------------------------------------------------  
  42. c、TYPE: Type of the SQL profile (how it was created):MANUAL  AUTO-TUNE  
  43. --  该列表明对应的sql profile是自动还是手动产生的    
  44.   
  45. -------------------------------------------------------------------------------------------------------------------  
  46. d、STATUS: Status of the SQL profile: ENABLED DISABLED VOID  
  47. --  该列表明对于sql profile是否处于启用状态   
  48.   
  49. -------------------------------------------------------------------------------------------------------------------  
  50. e、FORCE_MATCHING   
  51. --  If TRUE this causes SQL Profiles to target all SQL statements which have the same text after normalizing all literal values to bind variables.   
  52. --  (Note that if a combination of literal values and bind variables is used in the same SQL text, no transformation occurs).   
  53. --  This is analogous to the matching algorithm use by the FORCE option of the CURSOR_SHARING parameter.   
  54. --  If FALSE, literals are not transformed.   
  55. --  This is analogous to the matching algorithm used by the EXACT option of the CURSOR_SHARING parameter.  
  56.   --FORCE_MATCHING描述了SQL文本是模糊匹配还是精确匹配  
  57.   --为true时等同于CURSOR_SHARING参数的force,不区分空格,大小写及字面量。如果字面量与绑定变量混合则产生不同的签名ID  
  58.   --为false时等同于CURSOR_SHARING参数的exact,不区分空格和大小写  
  59.   --CURSOR_SHARING参数设置影响解析,字面量产生硬解析,绑定变量产生软解析(library cache中对应的sql存在时,可以参考Oracle硬解析与软解析  
  60.   --字面量与绑定变量  
  61.     select * from scott.emp where ename='SCOTT';  --SCOTT即是字面量  
  62.     select * from scott.emp where ename=:b1;      --b1即是绑定变量  
  63.   
  64. --上面的查询结果为no,也就是说此时使用的是缺省值false.  
  65. --前面我们完成tuning后生成的report中提到了建议接受一个profile以及remove提示ordered  
  66. --那我们看看接受sql profile之后Oracle到底干了什么  
  67. --从下面的查询可知,sql profile告诉优化器忽略该SQL语句中的提示,这就是他做的事情  
  68. hr@CNMMBO> SELECT attr_val  
  69.   2    FROM sys.sqlprof$ p, sys.sqlprof$attr a  
  70.   3   WHERE p.sp_name = 'hr_profile' AND p.signature = a.signature AND p.category = a.category;  
  71.   
  72. ATTR_VAL  
  73. --------------------------------------------------------------------------------------------------  
  74. IGNORE_OPTIM_EMBEDDED_HINTS               

3、测试接受SQL profile后的情形

[sql] view plaincopyprint?
  1. --对于OLTP的情形,大部分SQL语句使用了绑定变量,下面来测试一下绑定变量是否影响sql profile的运用  
  2. --以及测试SQL语句在使用大小写,添加或移除空格的情形时sql profile是否被使用到   
  3. hr@CNMMBO> variable bnd number;  --定义绑定变量并赋值   
  4. hr@CNMMBO> exec :bnd:=166     
  5.   
  6. PL/SQL procedure successfully completed.  
  7.   
  8. hr@CNMMBO> set autot trace exp;         
  9. hr@CNMMBO> SELECT       /*+ ORDERED */  
  10.   2  *  
  11.   3  FROM employees e, locations l, departments d  
  12.   4  WHERE e.department_id = d.department_id AND l.location_id =  
  13.   5  d.location_id AND e.employee_id < :bnd;  
  14.   
  15. Execution Plan  
  16. ----------------------------------------------------------  
  17. Plan hash value: 685643925  
  18.   
  19. ------------------------------------------------------------------------------------------------  
  20. | Id  | Operation                      | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
  21. ------------------------------------------------------------------------------------------------  
  22. |   0 | SELECT STATEMENT               |               |     5 |   685 |     9  (23)| 00:00:01 |  
  23. |*  1 |  HASH JOIN                     |               |     5 |   685 |     9  (23)| 00:00:01 |  
  24. |   2 |   MERGE JOIN                   |               |     5 |   440 |     5  (20)| 00:00:01 |  
  25. |   3 |    TABLE ACCESS BY INDEX ROWID | DEPARTMENTS   |    27 |   540 |     2   (0)| 00:00:01 |  
  26. |   4 |     INDEX FULL SCAN            | DEPT_ID_PK    |    27 |       |     1   (0)| 00:00:01 |  
  27. |*  5 |    SORT JOIN                   |               |     5 |   340 |     3  (34)| 00:00:01 |  
  28. |   6 |     TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     5 |   340 |     2   (0)| 00:00:01 |  
  29. |*  7 |      INDEX RANGE SCAN          | EMP_EMP_ID_PK |     2 |       |     1   (0)| 00:00:01 |  
  30. |   8 |   TABLE ACCESS FULL            | LOCATIONS     |    23 |  1127 |     3   (0)| 00:00:01 |  
  31. ------------------------------------------------------------------------------------------------  
  32.   
  33. Predicate Information (identified by operation id):  
  34. ---------------------------------------------------  
  35.   
  36.    1 - access("L"."LOCATION_ID"="D"."LOCATION_ID")  
  37.    5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")  
  38.        filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")  
  39.    7 - access("E"."EMPLOYEE_ID"<TO_NUMBER(:BND))  
  40.   
  41. Note  
  42. -----  
  43.    - SQL profile "hr_profile" used for this statement   --->这个提示表明sql profile已经被使用    
  44.   
  45. --下面我们给绑定变量重新赋值,以及使用小写来替换原来的SQL语句,并且移除一些空格,看看profile是否依旧会被使用  
  46. hr@CNMMBO> exec :bnd:=133;  
  47.   
  48. PL/SQL procedure successfully completed.  
  49.   
  50. hr@CNMMBO> select /*+ ORDERED */ * from employees e, locations l, departments d  
  51.   2  where e.department_id = d.department_id AND l.location_id = d.location_id  
  52.   3  and e.employee_id < :bnd;  
  53.   
  54. Execution Plan  
  55. ----------------------------------------------------------  
  56. Plan hash value: 685643925  
  57.   
  58. ------------------------------------------------------------------------------------------------  
  59. | Id  | Operation                      | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
  60. ------------------------------------------------------------------------------------------------  
  61. |   0 | SELECT STATEMENT               |               |     5 |   685 |     9  (23)| 00:00:01 |  
  62. |*  1 |  HASH JOIN                     |               |     5 |   685 |     9  (23)| 00:00:01 |  
  63. |   2 |   MERGE JOIN                   |               |     5 |   440 |     5  (20)| 00:00:01 |  
  64. |   3 |    TABLE ACCESS BY INDEX ROWID | DEPARTMENTS   |    27 |   540 |     2   (0)| 00:00:01 |  
  65. |   4 |     INDEX FULL SCAN            | DEPT_ID_PK    |    27 |       |     1   (0)| 00:00:01 |  
  66. |*  5 |    SORT JOIN                   |               |     5 |   340 |     3  (34)| 00:00:01 |  
  67. |   6 |     TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     5 |   340 |     2   (0)| 00:00:01 |  
  68. |*  7 |      INDEX RANGE SCAN          | EMP_EMP_ID_PK |     2 |       |     1   (0)| 00:00:01 |  
  69. |   8 |   TABLE ACCESS FULL            | LOCATIONS     |    23 |  1127 |     3   (0)| 00:00:01 |  
  70. ------------------------------------------------------------------------------------------------  
  71.   
  72. Predicate Information (identified by operation id):  
  73. ---------------------------------------------------  
  74.   
  75.    1 - access("L"."LOCATION_ID"="D"."LOCATION_ID")  
  76.    5 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")  
  77.        filter("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")  
  78.    7 - access("E"."EMPLOYEE_ID"<TO_NUMBER(:BND))  
  79.   
  80. Note  
  81. -----  
  82.    - SQL profile "hr_profile" used for this statement    --->这个提示表明sql profile已经被使用                               
  83.   
  84. --从上面的测试可知,大小写差异,空格多少以及绑定变量对上面的SQL语句并没有影响,之前的profile依旧有效  

4、对比优化前后的I/O 开销

[sql] view plaincopyprint?
  1. a、先测试优化后的I/O cost  
  2. hr@CNMMBO> set autot trace stat;  
  3. hr@CNMMBO> select /*+ ORDERED */ * from employees e, locations l, departments d  
  4.   2  where e.department_id = d.department_id AND l.location_id = d.location_id  
  5.   3  and e.employee_id < :bnd;  
  6.   
  7. 33 rows selected.  
  8.   
  9. Statistics  
  10. ----------------------------------------------------------  
  11.           0  recursive calls  
  12.           0  db block gets  
  13.          14  consistent gets  
  14.          10  physical reads  
  15.           0  redo size  
  16.        5362  bytes sent via SQL*Net to client  
  17.         514  bytes received via SQL*Net from client  
  18.           4  SQL*Net roundtrips to/from client  
  19.           1  sorts (memory)  
  20.           0  sorts (disk)  
  21.          33  rows processed  
  22.   
  23. --上面的Statistics表明优化后的consistent gets为14,physical reads为10  
  24.   
  25. --将sql profile disable,则该profile不会生效  
  26. hr@CNMMBO> set autot off;     
  27. hr@CNMMBO> BEGIN  
  28.   2     DBMS_SQLTUNE.alter_sql_profile (name => 'hr_profile', attribute_name => 'STATUS', VALUE => 'DISABLED');  
  29.   3  END;  
  30.   4  /  
  31.   
  32. PL/SQL procedure successfully completed.     
  33.   
  34. --Author : Robinson  
  35. --Blog   : http://blog.csdn.net/robinson_0612  
  36.   
  37. -->查看disable后的状态  
  38. hr@CNMMBO> select name,status from dba_sql_profiles where name='hr_profile';  
  39.   
  40. NAME                           STATUS  
  41. ------------------------------ --------  
  42. hr_profile                     DISABLED  
  43.   
  44. hr@CNMMBO> print bnd;  
  45.   
  46.        BND  
  47. ----------  
  48.        133  
  49.   
  50. --下面来查看disable后的统计信息,SQL语句会回到优化之前         
  51. hr@CNMMBO> set autot trace stat;  
  52. hr@CNMMBO> select /*+ ORDERED */ * from employees e, locations l, departments d  
  53.   2  where e.department_id = d.department_id AND l.location_id = d.location_id  
  54.   3  and e.employee_id < :bnd;  
  55.   
  56. 33 rows selected.  
  57.   
  58. Statistics  
  59. ----------------------------------------------------------  
  60.           9  recursive calls  
  61.           0  db block gets  
  62.          27  consistent gets  
  63.           5  physical reads  
  64.           0  redo size  
  65.        5403  bytes sent via SQL*Net to client  
  66.         514  bytes received via SQL*Net from client  
  67.           4  SQL*Net roundtrips to/from client  
  68.           1  sorts (memory)  
  69.           0  sorts (disk)  
  70.          33  rows processed  
  71.   
  72. --从上面的统计信息可知,SQL优化之前的consistent gets为27,大于优化之后的consistent gets  
  73. --注,此处未对比physical reads,一般情形下我们考虑的是consistent gets,如果需要两个都对比,应每次执行SQL前flush buffer cache  
  74.   
  75. -->接下来可以移除sql profile  
  76. hr@CNMMBO> set autot off;  
  77. hr@CNMMBO> exec dbms_sqltune.drop_sql_profile('hr_profile');  
  78.   
  79. PL/SQL procedure successfully completed.           

5、使用STA优化awr中SQL的脚本

[sql] view plaincopyprint?
  1. robin@SZDB:~/dba_scripts/custom/sql> more tune_awr_sql.sql   
  2. SET ECHO OFF TERMOUT ON FEEDBACK OFF VERIFY OFF    
  3. SET SCAN ON PAGESIZE 9999   
  4. SET LONG 1000000 LINESIZE 180  
  5. COL recs FORMAT a145  
  6. --Author : Robinson  
  7. --Blog   : http://blog.csdn.net/robinson_0612  
  8.   
  9. VARIABLE tuning_task VARCHAR2(30)  
  10.   
  11. DECLARE  
  12.   l_sql_id v$session.prev_sql_id%TYPE:='&input_sql_id';  
  13. BEGIN  
  14.   :tuning_task := dbms_sqltune.create_tuning_task(sql_id => l_sql_id,  
  15.                      begin_snap=>&input_begin_snap,  
  16.                      end_snap=>&input_end_snap,  
  17.                      task_name=>'&input_task_name');  
  18.   dbms_sqltune.execute_tuning_task(:tuning_task);  
  19. END;  
  20. /  
  21.   
  22. SELECT dbms_sqltune.report_tuning_task(:tuning_task) as recs   
  23. FROM dual;  
  24.   
  25. SET VERIFY ON FEEDBACK ON   


6、小结

a、SQL优化器在tuning模式下不会对原始SQL语句文本做任何修改。
b、对于使用STA优化的SQL语句,SQL优化器会转换优化器的模式或移除添加hint(如本例是忽略hint)以实现优化。
c、SQL profile会纠正查询优化器对基数的错误评估。
d、对于统计信息缺失或过时或根本不存在统计信息的情形,SQL优化器会给出建议以获取真实的统计信息。
e、SQL profile能够被导入导出。导出之前,该profile必须先被accept。
f、SQL profile所依赖的对象被删除后,SQL profile并不会被删除。但如果使用drop user username cascade时是例外。


Forward from http://blog.csdn.net/leshami/article/details/9054431


0 0