使用SQL tuning advisor(STA)自动优化SQL

Oracle 10g之后的优化器支持两种模式,一个是normal模式,一个是tuning模式。在大多数情况下,优化器处于normal模式。基于CBO的normal模式只考虑很小部分的执行计划集合用于选择哪个执行计划,因为它需要在尽可能短的时间,通常是几秒或毫秒级来对当前的SQL语句进行解析并生成执行计划。因此并不能保证SQL语句每次都是使用最佳的执行计划。而tuning模式则将高负载的SQL语句直接扔给优化器,优化器来自动对其进行详细的分析,调试并给出建议,这就是Oracle 提供的Automatic Tuning Optimizer,即自动调整优化器。Oracle 自动调整优化器通过SQL调优建议器(SQL tuning advisor)来体现。

 

1、SQL tuning的基本步骤
     a、鉴别需要调整的高负载SQL或者Top SQL
     b、寻找可改进的执行计划
     c、实施能够改进的执行计划以提高SQL效率
  
2、如何tuning SQL
     a、检查是否为优化器设置了合理的参数(optimizer_mode,optimizer_index_caching,optimizer_index_cost_adj,以及相关cache size)
     b、检查SQL语句所涉及的对象是否存在过时的统计信息或者倾斜列是否缺少直方图等
     c、通过添加提示来引导SQL语句使用正确的访问路径,以及连接方式等
     d、重构等价的SQL语句以使得SQL更高效(如最小化基表及中间结果集,避免列运算,列上的函数,null值,不等运算使得索引失效)
     e、添加合理的索引或物化视图以及移除冗余索引,分散I/O等
  
3、Automatic Tuning Optimizer 做什么?
     a、分析统计信息
         优化器执行计划产生期间记录当前SQL语句涉及对象的统计信息的类型以及哪些被使用或哪些是需要的
         当统计信息记录完成后自动调整优化器会比对与查询相关的这些对象的统计信息是否可用或过时或非均衡列缺少直方图等
         针对上述的操作之后得到哪些对象没有统计信息以及哪些对象缺少统计信息以及额外的统计信息用于生成report     
     b、分析访问路径
         优化器会分析当前SQL所使用的访问路径是否合理,也就是分析基于表的访问方式,如全表扫描,索引扫描等
         自动调整优化器会基于谓词尝试假设性的推断来创建合理的索引,也就是建议通过添加或修改相应的索引来提高性能
     c、SQL结构分析
         优化器会建议对于一些具有较大影响的SQL语句作结构性调整及转换(基于内部规则),如未嵌套的子查询,重写物化视图,视图合并等
         基于语法以及语义结构的分析与调整,如谓词列上的运算,UNION与UNION ALL的使用,NOT IN, NOT EXIST之间替换等
         对中间结果集以及连接方式等实现一些预估的分析
     d、SQL profiling
         SQL profiling 内置于优化器,就是一个剖析工具,基于上述得到的信息对当前的SQL进行剖析,以检查出导致性能糟糕的故障点
         所有上述分析得到的结果以及辅助信息最后以sql profile的形式表现出来,供用户来判断是否接受
         当用户接受这些profile,下次处于normal模式时,相同的sql语句会使用这个profile
         可以对profile进行启用,停用,以及修改,因此即使表发生较大的变化,profile依旧能使得SQL受益

 

4、Automatic Tuning Optimizer与SQL tuning advisor结构图 

使用SQL tuning advisor(STA)自动优化SQL_第1张图片 

5、STA可tuning的方式
     STA提供OEM图形界面以及API方式进行tuning,本文主要描述API即dbms_sqltune.create_tuning_task方式
     下面是可被create_tuning_task接受的API方式
       a、直接提供SQL语句文本
       b、引用共享池中的SQL语句(sql_id)
       c、引用awr自动工作负载中的SQL语句(sql_id)
       d、建议SQL调优集(批量tuning)
  
6、演示SQL tuning 

[sql] view plain copy print ?
  1. --环境  
  2. scott@ORA11G> select * from v$version where rownum<2;  
  3.   
  4. BANNER  
  5. --------------------------------------------------------------------------------  
  6. Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production  
  7.   
  8. --创建演示表   
  9. scott@ORA11G> CREATE TABLE t  
  10.   2  NOLOGGING  
  11.   3  AS  
  12.   4     SELECT *  
  13.   5       FROM dba_source,  
  14.   6            (    SELECT *  
  15.   7                   FROM DUAL  
  16.   8             CONNECT BY ROWNUM < 5);  
  17.   
  18. Table created.  
  19.   
  20. --执行SQL 语句  
  21. scott@ORA11G> SELECT COUNT (*)  
  22.   2    FROM t a  
  23.   3   WHERE a.ROWID > (SELECT MIN (b.ROWID)  
  24.   4                      FROM t b  
  25.   5                     WHERE a.owner = b.owner AND a.name = b.name AND a.TYPE = b.TYPE AND a.line = b.line);  
  26.   
  27.   COUNT(*)  
  28. ----------  
  29.    1872756  
  30.   
  31. 1 row selected.  
  32.   
  33. --开始SQL自动调整并报告结果  
  34. --脚本tune_last_sql.sql中包含了创建调优任务、开始执行调优、以及报告调优成果。脚本内容见文章尾部  
  35. scott@ORA11G> @tune_last_sql  
  36.   
  37. RECS  
  38. -----------------------------------------------------------------------------------------  
  39. GENERAL INFORMATION SECTION  
  40. -------------------------------------------------------------------------------  
  41. Tuning Task Name   : TASK_833  
  42. Tuning Task Owner  : SCOTT  
  43. Workload Type      : Single SQL Statement  
  44. Scope              : COMPREHENSIVE  
  45. Time Limit(seconds): 1800  
  46. Completion Status  : COMPLETED  
  47. Started at         : 05/22/2013 15:06:06  
  48. Completed at       : 05/22/2013 15:07:17  
  49.   
  50. -------------------------------------------------------------------------------  
  51. Schema Name: SCOTT  
  52. SQL ID     : 44tg722u0ypqh  
  53. SQL Text   : SELECT COUNT (*)  
  54.                FROM t a  
  55.               WHERE a.ROWID > (SELECT MIN (b.ROWID)  
  56.                                  FROM t b  
  57.                                 WHERE a.owner = b.owner AND a.name = b.name  
  58.              AND a.TYPE = b.TYPE AND a.line = b.line)  
  59.   
  60. -------------------------------------------------------------------------------  
  61. FINDINGS SECTION (1 finding)  
  62. -------------------------------------------------------------------------------  
  63.   
  64. 1- Statistics Finding  
  65. ---------------------  
  66.   Table "SCOTT"."T" was not analyzed.  
  67.   
  68.   Recommendation  
  69.   --------------  
  70.   - Consider collecting optimizer statistics for this table.  
  71.     execute dbms_stats.gather_table_stats(ownname => 'SCOTT', tabname => 'T',  
  72.             estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt =>  
  73.             'FOR ALL COLUMNS SIZE AUTO');  
  74.   
  75.   Rationale  
  76.   ---------  
  77.     The optimizer requires up-to-date statistics for the table in order to  
  78.     select a good execution plan.  
  79.   
  80. -------------------------------------------------------------------------------  
  81. EXPLAIN PLANS SECTION  
  82. -------------------------------------------------------------------------------  
  83.   
  84. 1- Original  
  85. -----------  
  86. Plan hash value: 1985065416  
  87.   
  88. -----------------------------------------------------------------------------------------  
  89. | Id  | Operation             | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |  
  90. -----------------------------------------------------------------------------------------  
  91. |   0 | SELECT STATEMENT      |         |     1 |   134 |       | 42648   (1)| 00:08:32 |  
  92. |   1 |  SORT AGGREGATE       |         |     1 |   134 |       |            |          |  
  93. |*  2 |   HASH JOIN           |         |   129K|    16M|   195M| 42648   (1)| 00:08:32 |  
  94. |   3 |    TABLE ACCESS FULL  | T       |  2590K|   165M|       | 11596   (1)| 00:02:20 |  
  95. |   4 |    VIEW               | VW_SQ_1 |  2590K|   165M|       | 11674   (1)| 00:02:21 |  
  96. |   5 |     HASH GROUP BY     |         |  2590K|   165M|       | 11674   (1)| 00:02:21 |  
  97. |   6 |      TABLE ACCESS FULL| T       |  2590K|   165M|       | 11596   (1)| 00:02:20 |  
  98. -----------------------------------------------------------------------------------------  
  99.   
  100. Predicate Information (identified by operation id):  
  101. ---------------------------------------------------  
  102.   
  103.    2 - access("A"."OWNER"="ITEM_1" AND "A"."NAME"="ITEM_2" AND  
  104.               "A"."TYPE"="ITEM_3" AND "A"."LINE"="ITEM_4")  
  105.        filter("A".ROWID>"MIN(B.ROWID)")  
  106.   
  107. --上面的report总共分为3个部分,分别是SQL调优的基本信息、SQL调优的建议findings、以及SQL对应的执行计划部分  
  108. --在基本信息部分包含了SQL调优的任务名称,状态,执行,完成时间,对应的SQL完整语句等  
  109. --在finding部分则给出本次调优所得到的成果,如本次是提示缺少统计信息  
  110. --在执行计划部分则给出了当前SQL语句的执行计划以及谓词信息  
  111.   
  112. -->接下来根据建议来收集统计信息  
  113. scott@ORA11G> BEGIN  
  114.   2     DBMS_STATS.gather_table_stats (ownname            => 'SCOTT',  
  115.   3                                    tabname            => 'T',  
  116.   4                                    estimate_percent   => DBMS_STATS.auto_sample_size,  
  117.   5                                    method_opt         => 'FOR ALL COLUMNS SIZE AUTO');  
  118.   6  END;  
  119.   7  /  
  120.   
  121. PL/SQL procedure successfully completed.  
  122.   
  123. -->对原SQL语句增加order提示并执行  
  124. scott@ORA11G> SELECT /*+ ordered */COUNT (*)  
  125.   2    FROM t a  
  126.   3   WHERE a.ROWID > (SELECT MIN (b.ROWID)  
  127.   4                      FROM t b  
  128.   5                     WHERE a.owner = b.owner AND a.name = b.name AND a.TYPE = b.TYPE AND a.line = b.line);  
  129.   
  130.   COUNT(*)  
  131. ----------  
  132.    1872756  
  133.   
  134. 1 row selected.  
  135.   
  136. --再次调优SQL语句  
  137. scott@ORA11G> @tune_last_sql  
  138.   
  139. RECS  
  140. -----------------------------------------------------------------------------------------------  
  141. GENERAL INFORMATION SECTION  
  142. -------------------------------------------------------------------------------  
  143. Tuning Task Name   : TASK_849  
  144. Tuning Task Owner  : SCOTT  
  145. Workload Type      : Single SQL Statement  
  146. Scope              : COMPREHENSIVE  
  147. Time Limit(seconds): 1800  
  148. Completion Status  : COMPLETED  
  149. Started at         : 05/22/2013 21:26:07  
  150. Completed at       : 05/22/2013 21:26:42  
  151.   
  152. -------------------------------------------------------------------------------  
  153. Schema Name: SCOTT  
  154. SQL ID     : fsp3852n56gf8  
  155. SQL Text   : SELECT /*+ ordered */COUNT (*)  
  156.              FROM t a  
  157.              WHERE a.ROWID > (SELECT MIN (b.ROWID) from t b  
  158.              WHERE a.owner = b.owner AND a.name = b.name AND a.TYPE = b.TYPE  
  159.              AND a.line = b.line)  
  160.   
  161. -------------------------------------------------------------------------------  
  162. FINDINGS SECTION (1 finding)  
  163. -------------------------------------------------------------------------------  
  164.   
  165. 1- SQL Profile Finding (see explain plans section below)  
  166. --------------------------------------------------------  
  167.   A potentially better execution plan was found for this statement.  
  168.   
  169.   Recommendation (estimated benefit: 67.95%)  
  170.   ------------------------------------------  
  171.   - Consider accepting the recommended SQL profile.  
  172.     execute dbms_sqltune.accept_sql_profile(task_name => 'TASK_849',  
  173.             task_owner => 'SCOTT'replace => TRUE);  
  174.   
  175. -------------------------------------------------------------------------------  
  176. EXPLAIN PLANS SECTION  
  177. -------------------------------------------------------------------------------  
  178.   
  179. 1- Original With Adjusted Cost  
  180. ------------------------------  
  181. Plan hash value: 2929971977  
  182.   
  183. --------------------------------------------------------------------------------------------  
  184. | Id  | Operation              | Name      | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |  
  185. --------------------------------------------------------------------------------------------  
  186. |   0 | SELECT STATEMENT       |           |     1 |       |       |   218K  (1)| 00:43:47 |  
  187. |   1 |  SORT AGGREGATE        |           |     1 |       |       |            |          |  
  188. |   2 |   VIEW                 | VM_NWVW_2 |   551K|       |       |   218K  (1)| 00:43:47 |  
  189. |*  3 |    FILTER              |           |       |       |       |            |          |  
  190. |   4 |     HASH GROUP BY      |           |   551K|    51M|  1197M|   218K  (1)| 00:43:47 |  
  191. |*  5 |      HASH JOIN         |           |    11M|  1031M|   145M| 37646   (1)| 00:07:32 |  
  192. |   6 |       TABLE ACCESS FULL| T         |  2497K|   116M|       | 11596   (1)| 00:02:20 |  
  193. |   7 |       TABLE ACCESS FULL| T         |  2497K|   116M|       | 11596   (1)| 00:02:20 |  
  194. --------------------------------------------------------------------------------------------  
  195.   
  196. Predicate Information (identified by operation id):  
  197. ---------------------------------------------------  
  198.   
  199.    3 - filter("A".ROWID>MIN("B".ROWID))  
  200.    5 - access("A"."OWNER"="B"."OWNER" AND "A"."NAME"="B"."NAME" AND  
  201.               "A"."TYPE"="B"."TYPE" AND "A"."LINE"="B"."LINE")  
  202.   
  203. 2- Using SQL Profile  
  204. --------------------  
  205. Plan hash value: 1985065416  
  206.   
  207. -----------------------------------------------------------------------------------------  
  208. | Id  | Operation             | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |  
  209. -----------------------------------------------------------------------------------------  
  210. |   0 | SELECT STATEMENT      |         |     1 |   116 |       | 70117   (1)| 00:14:02 |  
  211. |   1 |  SORT AGGREGATE       |         |     1 |   116 |       |            |          |  
  212. |*  2 |   HASH JOIN           |         |  2025K|   224M|   145M| 70117   (1)| 00:14:02 |  
  213. |   3 |    TABLE ACCESS FULL  | T       |  2497K|   116M|       | 11596   (1)| 00:02:20 |  
  214. |   4 |    VIEW               | VW_SQ_1 |  2497K|   159M|       | 41851   (1)| 00:08:23 |  
  215. |   5 |     HASH GROUP BY     |         |  2497K|   116M|   153M| 41851   (1)| 00:08:23 |  
  216. |   6 |      TABLE ACCESS FULL| T       |  2497K|   116M|       | 11596   (1)| 00:02:20 |  
  217. -----------------------------------------------------------------------------------------  
  218.   
  219. Predicate Information (identified by operation id):  
  220. ---------------------------------------------------  
  221.   
  222.    2 - access("A"."OWNER"="ITEM_1" AND "A"."NAME"="ITEM_2" AND  
  223.               "A"."TYPE"="ITEM_3" AND "A"."LINE"="ITEM_4")  
  224.        filter("A".ROWID>"MIN(B.ROWID)")  
  225.   
  226. -------------------------------------------------------------------------------  
  227.   
  228. --针对上述的SQL语句,SQL调优器找到了一个更为高效的执行计划,并提示我们接受该执行计划,如下  
  229. --A potentially better execution plan was found for this statement.  
  230. --Recommendation (estimated benefit: 67.95%)  
  231. --Consider accepting the recommended SQL profile  
  232.   
  233. --Author : Robinson  
  234. --Blog   : http://blog.csdn.net/robinson_0612  
  235.   
  236. --接受SQL profile  
  237. scott@ORA11G> exec DBMS_SQLTUNE.accept_sql_profile (task_name => 'TASK_849', task_owner => 'SCOTT'REPLACE => TRUE);  
  238.   
  239. PL/SQL procedure successfully completed.  
  240.   
  241. --当接受SQL profile后,我们再次来执行原来带order提示的SQL语句  
  242. scott@ORA11G> set autot trace exp;  
  243. scott@ORA11G> SELECT /*+ ordered */COUNT (*)  
  244.   2               FROM t a  
  245.   3               WHERE a.ROWID > (SELECT MIN (b.ROWID) from t b  
  246.   4               WHERE a.owner = b.owner AND a.name = b.name AND a.TYPE = b.TYPE  
  247.   5               AND a.line = b.line);  
  248.   
  249. Execution Plan  
  250. ----------------------------------------------------------  
  251. Plan hash value: 1985065416  
  252.   
  253. -----------------------------------------------------------------------------------------  
  254. | Id  | Operation             | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |  
  255. -----------------------------------------------------------------------------------------  
  256. |   0 | SELECT STATEMENT      |         |     1 |   116 |       | 70117   (1)| 00:14:02 |  
  257. |   1 |  SORT AGGREGATE       |         |     1 |   116 |       |            |          |  
  258. |*  2 |   HASH JOIN           |         |  2025K|   224M|   145M| 70117   (1)| 00:14:02 |  
  259. |   3 |    TABLE ACCESS FULL  | T       |  2497K|   116M|       | 11596   (1)| 00:02:20 |  
  260. |   4 |    VIEW               | VW_SQ_1 |  2497K|   159M|       | 41851   (1)| 00:08:23 |  
  261. |   5 |     HASH GROUP BY     |         |  2497K|   116M|   153M| 41851   (1)| 00:08:23 |  
  262. |   6 |      TABLE ACCESS FULL| T       |  2497K|   116M|       | 11596   (1)| 00:02:20 |  
  263. -----------------------------------------------------------------------------------------  
  264.   
  265. Predicate Information (identified by operation id):  
  266. ---------------------------------------------------  
  267.   
  268.    2 - access("A"."OWNER"="ITEM_1" AND "A"."NAME"="ITEM_2" AND  
  269.               "A"."TYPE"="ITEM_3" AND "A"."LINE"="ITEM_4")  
  270.        filter("A".ROWID>"MIN(B.ROWID)")  
  271.   
  272. Note  
  273. -----  
  274.    - SQL profile "SYS_SQLPROF_013ecc70b5f70000" used for this statement  
  275.   
  276. scott@ORA11G> set autot off;  
  277.   
  278. --上面的autotrace中,最后一部分表明当前的SQL语句使用了存储的SQL profile的执行计划  

7、相关视图
     DBA_ADVISOR_LOG
     DBA_ADVISOR_TASKS
     DBA_ADVISOR_FINDINGS
     DBA_ADVISOR_RECOMMENDATIONS
     DBA_ADVISOR_RATIONALE
     DBA_SQLTUNE_STATISTICS
     DBA_SQLTUNE_BINDS
     DBA_SQLTUNE_PLANS

8、演示用到的脚本

[sql] view plain copy print ?
  1. SET ECHO OFF TERMOUT ON FEEDBACK OFF VERIFY OFF    
  2. SET SCAN ON  
  3. SET LONG 1000000 LINESIZE 180  
  4. COL recs FORMAT a135  
  5.   
  6. VARIABLE tuning_task VARCHAR2(30)  
  7.   
  8. DECLARE  
  9.   l_sql_id v$session.prev_sql_id%TYPE;  
  10. BEGIN  
  11.   SELECT prev_sql_id INTO l_sql_id  
  12.   FROM v$session  
  13.   WHERE audsid = userenv('SESSIONID');  
  14.     
  15.   :tuning_task := dbms_sqltune.create_tuning_task(sql_id => l_sql_id);  
  16.   dbms_sqltune.execute_tuning_task(:tuning_task);  
  17. END;  
  18. /  
  19.   
  20. SELECT dbms_sqltune.report_tuning_task(:tuning_task) as recs   
  21. FROM dual;  
  22.   
  23. SET VERIFY ON FEEDBACK ON  
Forward from http://blog.csdn.net/leshami/article/details/8996253

你可能感兴趣的:(使用SQL tuning advisor(STA)自动优化SQL)