1、前言:一直以来SQL调优都是DBA比较费力的技术活,而且很多DBA如果没有从事过开发的工作,那么调优更是一项头疼的工作,即使是SQL调优很厉害的高手,在SQL调优的过程中也要不停的分析执行计划、加HINT、分析统计信息等等。从ORACLE 10G开始,数据库采取了很多智能化的管理工作,其中SQL优化器(SQL Tuning Advisor:STA),大大的提高了DBA进行SQL优化的效率;
2、原理介绍:
When SQL statements are executed by the Oracle database, the query optimizer is used to generate the execution plans of the SQL statements. The query optimizer operates in two modes: a normal mode and a tuning mode.
In normal mode, the optimizer compiles the SQL and generates an execution plan. The normal mode of the optimizer generates a reasonable execution plan for the vast majority of SQL statements. Under normal mode, the optimizer operates with very strict time constraints, usually a fraction of a second, during which it must find a good execution plan.
In tuning mode, the optimizer performs additional analysis to check whether the execution plan produced under normal mode can be improved further. The output of the query optimizer is not an execution plan, but a series of actions, along with their rationale and expected benefit for producing a significantly superior plan. When running in the tuning mode, the optimizer is referred to as the Automatic Tuning Optimizer.
Under tuning mode, the optimizer can take several minutes to tune a single statement. It is both time and resource intensive to invoke the Automatic Tuning Optimizer every time a query has to be hard-parsed. The Automatic Tuning Optimizer is meant to be used for complex and high-load SQL statements that have non-trivial impact on the entire system. The Automatic Database Diagnostic Monitor (ADDM) proactively identifies high-load SQL statements which are good candidates for SQL tuning. See Chapter 6, "Automatic Performance Diagnostics". The automatic SQL tuning feature of Oracle Database also automatically identifies problematic SQL statements and implements tuning recommendations during system maintenance windows as an automated maintenance task.
查询优化器有两种模式:普通模式与调化模式。
优化器在普通模式下,当SQL被执行时,查询优化器将生成SQL的执行计划,如果SQL的可选路径很多,优化器必须是限制时间内,选择一个合适的执行计划,查询优化器默认执行普通模式;
当优化器在调优模式下,优化器需要执行额外的分析去判断优化器在普通模式下产生的执行计划是否有可能被改进,此时优化器输出的不是一个执行计划,而是一系列的动作,根据调优的原理、产生一个更优化的执行计划,优化器需发花费一定的时间去调优单个的sql,自动调优的优化器每次查询都是硬解析。
SQL Tuning Advisor获取AWR报告中High-Load SQL,查询优化器在调优模式下生成一个最好的执行计划,从而实现SQL调优的目的;
3、功能介绍:
The Automatic Tuning Optimizer performs four types of tuning analysis:
- Statistics Analysis
- SQL Profiling
- Access Path Analysis
- SQL Structure Analysis
4、SQL Tuning Advisor的管理:
任务的查看:select * from DBA_AUTOTASK_WINDOW_CLIENTS;
任务的启动:
BEGINDBMS_AUTO_TASK_ADMIN.ENABLE(client_name => 'sql tuning advisor',operation => NULL,window_name => NULL);END;/
任务的停止:BEGINDBMS_AUTO_TASK_ADMIN.DISABLE(client_name => 'sql tuning advisor',operation => NULL,window_name => NULL);END;/
SQL Tuning Advisor结果的查看:
select dbms_sqltune.report_tuning_task('SYS_AUTO_SQL_TUNING_TASK') from dual;
5、手工运行SQL Tuning Advisor进行调优
说明:创建两张大表和小表,并且都没创建索引,然后进行关联。通过执行SQL Tuning Advisor得到优化建议
步骤一:创建表
脚本:create table hr.big as select rownum as "id",a.* from sys.all_objects a;
脚本:create table hr.small as select rownum as "id", a.* FROM sys.all_tables a;
然后多运行几次下面的脚本,增加表里的数据:
insert into hr.big select * from hr.big;
insert into hr.small select * from hr.small;
SQL> select count(*) from hr.small;
COUNT(*) ---------- 2835
SQL> select count(*) from hr.big;
COUNT(*) ---------- 727438 |
步骤二:直接进行关联测试
SQL> set timing on SQL> set autot on SQL> select count(*) from hr.big a, hr.small b where a.object_name=b.table_name;
COUNT(*) ---------- 31500
Elapsed: 00:00:00.50
Execution Plan ---------------------------------------------------------- Plan hash value: 1355302734
----------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 34 | 3064 (1)| 00:00:37 | | 1 | SORT AGGREGATE | | 1 | 34 | | | |* 2 | HASH JOIN | | 453K| 14M| 3064 (1)| 00:00:37 | | 3 | TABLE ACCESS FULL| SMALL | 2915 | 49555 | 31 (0)| 00:00:01 | | 4 | TABLE ACCESS FULL| BIG | 610K| 9M| 3029 (1)| 00:00:37 | -----------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
2 - access("A"."OBJECT_NAME"="B"."TABLE_NAME")
Note ----- - dynamic sampling used for this statement (level=2)
Statistics ---------------------------------------------------------- 10 recursive calls 2 db block gets 11362 consistent gets 6332 physical reads 0 redo size 527 bytes sent via SQL*Net to client 523 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 2 sorts (memory) 0 sorts (disk) 1 rows processed |
步骤三:创建优化任务
通过调用函数CREATE_TUNING_TASK来创建优化任务,调用存储过程EXECUTE_TUNING_TASK执行该任务:
SQL> set autot off SQL> set timing off SQL> DECLARE my_task_name VARCHAR2(30); my_sqltext CLOB; BEGIN my_sqltext := 'select count(*) from hr.big a, hr.small b where a.object_name=b.table_name'; my_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK( sql_text => my_sqltext, user_name => 'HR', scope => 'COMPREHENSIVE', time_limit => 60, task_name => 'tuning_sql_test', description => 'Task to tune a query on a specified table'); DBMS_SQLTUNE.EXECUTE_TUNING_TASK( task_name => 'tuning_sql_test'); END; / |
函数CREATE_TUNING_TASK说明:
- sql_text是需要优化的语句
- user_name是该语句通过哪个用户执行,注意是大写,不然会报错,用户无效
- scope是优化范围(limited或comprehensive),
- time_limit优化过程的时间限制,
- task_name优化任务名称,
- description优化任务描述。
步骤四: 执行优化任务
通过调用dbms_sqltune.execute_tuning_task过程来执行前面创建好的优化任务。
SQL> exec dbms_sqltune.execute_tuning_task('tuning_sql_test'); |
步骤五:检查优化任务的状态
通过查看user_advisor_tasks/dba_advisor_tasks视图可以查看优化任务的当前状态。
SQL> SELECT task_name,status FROM USER_ADVISOR_TASKS WHERE task_name='tuning_sql_test'; TASK_NAME STATUS ---------------- -------------- ----------- tuning_sql_test COMPLETED |
步骤六:查看优化结果
通过dbms_sqltune.report_tning_task函数可以获得优化任务的结果。
SQL> SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK( 'tuning_sql_test') from DUAL;
GENERAL INFORMATION SECTION ------------------------------------------------------------------------------- Tuning Task Name : tuning_sql_test Tuning Task Owner : SYS Workload Type : Single SQL Statement Execution Count : 2 Current Execution : EXEC_12 Execution Type : TUNE SQL Scope : COMPREHENSIVE Time Limit(seconds): 60 Completion Status : COMPLETED Started at : 12/30/2013 15:56:04 Completed at : 12/30/2013 15:56:06
------------------------------------------------------------------------------- Schema Name: HR SQL ID : 6fnz11x82cuv4 SQL Text : select count(*) from hr.big a, hr.small b where a.object_name=b.table_name
------------------------------------------------------------------------------- FINDINGS SECTION (3 findings) -------------------------------------------------------------------------------
1- Statistics Finding --------------------- ????? "HR"."SMALL"?
Recommendation -------------- - ???????????????? execute dbms_stats.gather_table_stats(ownname => 'HR', tabname => 'SMALL', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt => 'FOR ALL COLUMNS SIZE AUTO');
Rationale --------- ??????????, ????????????????
2- Statistics Finding --------------------- ????? "HR"."BIG"?
Recommendation -------------- - ???????????????? execute dbms_stats.gather_table_stats(ownname => 'HR', tabname => 'BIG', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt => 'FOR ALL COLUMNS SIZE AUTO');
Rationale --------- ??????????, ????????????????
3- Index Finding (see explain plans section below) -------------------------------------------------- ????????????????????????
Recommendation (estimated benefit: 67.55%) ------------------------------------------ - ????????????????????????????? create index HR.IDX$$_00150001 on HR.SMALL("TABLE_NAME");
- ????????????????????????????? create index HR.IDX$$_00150002 on HR.BIG("OBJECT_NAME");
Rationale --------- ?????????????????????????, ????? SQL ????? "????" ?????????????????????????????, ????????????????????
------------------------------------------------------------------------------- EXPLAIN PLANS SECTION -------------------------------------------------------------------------------
1- Original ----------- Plan hash value: 1355302734
----------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 34 | 3064 (1)| 00:00:37 | | 1 | SORT AGGREGATE | | 1 | 34 | | | |* 2 | HASH JOIN | | 453K| 14M| 3064 (1)| 00:00:37 | | 3 | TABLE ACCESS FULL| SMALL | 2915 | 49555 | 31 (0)| 00:00:01 | | 4 | TABLE ACCESS FULL| BIG | 610K| 9M| 3029 (1)| 00:00:37 | -----------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
2 - access("A"."OBJECT_NAME"="B"."TABLE_NAME")
2- Using New Indices -------------------- Plan hash value: 3519661237
----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 34 | 994 (2)| 00:00:12 | | 1 | SORT AGGREGATE | | 1 | 34 | | | |* 2 | HASH JOIN | | 453K| 14M| 994 (2)| 00:00:12 | | 3 | INDEX FAST FULL SCAN| IDX$$_00150001 | 2915 | 49555 | 12 (0)| 00:00:01 | | 4 | INDEX FAST FULL SCAN| IDX$$_00150002 | 610K| 9M| 978 (1)| 00:00:12 | -----------------------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
2 - access("A"."OBJECT_NAME"="B"."TABLE_NAME")
------------------------------------------------------------------------------- |
解读报告:
红色部分:关于这次优化任务的基本信息:如任务名称、执行时间、范围、涉及到的语句等等。
绿色部分:关于这次优化任务的所找到的问题以及给出的优化建议。
- 运行SMALL表的统计信息的收集;
- 运行BIG表统计信息的收集;
- 进行索引的添加;
蓝色部分:优化前和优化后的执行计划的对比,可以看出COST值大大下降。
五、删除优化任务
通过调用dbms_sqltuen.drop_tuning_task可以删除已经存在的优化任务
SQL>exec dbms_sqltune.drop_tuning_task('tuning_sql_test');
PL/SQL procedure successfully completed.
总结:SQL Tuning Advisor为DBA的调优工作减轻了不少负担,一般情况下我也是通过这种方法进行调优的,这里有点小小的建议:
- 工具毕竟是固定的,一般只会针对单个语句给出建议,不会在整个数据库的整体性能上面去思考该调优方法是否可行,这点必须由DBA把握;
- DBA还是有必要了解为什么要这么调优,才能更好的根据实际情况给出具体的调优办法,不然调优这种高大上的工作将变得廉价。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
本文作者:JOHN
ORACLE技术博客:ORACLE 猎人笔记 数据库技术群:367875324 (请备注ORACLE管理 )
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++