在日常的工作中,如何及时发现数据库潜在的问题是极为重要的。对于数据库性能的诊断可分为三个阶段:
第一阶段:SQL语句级性能优化
第二阶段:session级性能优化,可通过ASH配合分析
第三阶段:DB级性能优化,可通过AWR进行分析。
AWR:AutomaticWorkload Repository 自动工作负载信息库
AWR是数据库实例级的诊断报告,通过对系统整体动态采样收集快照信息,存储在SYSAUX表空间,每小时采样一次(养老金系统在生产上每半个小时采样一次),可以保存7天,MMON进程实施,快照分析后写入DBA_HIST_%开头的数据字典。
ASH:ActiveSession History 活动会话历史记录
ASH是一个会话级别的性能诊断报告,可以提供更细粒度的时间区间,可以精确到分钟,ASH可以提供比AWR更详细的关于历史会话的信息,可以作为AWR的补充。
分析ASH报告、AWR报告的时候,重点关注SQL Statistics 。SQL Statistics中应该关注的是SQL ordered by Gets和SQL ordered by Reads两个指标。大量的Gets(逻辑读)会占用大量的CPU时间。大量的Reads(物理读)会引起IO的瓶颈出现。
Awrrpt.sql:获取本实例中的awr报告
Awrrpti.sql:获取指定实例的awr报告
Awrsqrpt.sql:获取某个SQL的awr报告
Awrsqrpi.sql:获取指定实例的某个SQL的awr报告
Awrddrpt.sql:对比两个时间段的报告
awrddrpi.sql:获取指定实例中的两个时间段的报告
由于AWR机制是在小时级别上对数据库进行采样,对于业务量很大的系统而言,可能会出现短时间的性能问题,但是在小时级别上未能被AWR监控到,因此可通过ASH进行辅助观察。
在生成ASH报告(ASHRPT.SQL)之后,可以重新检索哪些标识为短暂性能问题的信息。ASH报告的内容分成了以下几个部分:
TopEvents:顶级等待事件部分描述了被抽样会话活动中由用户,后台等产生的顶级等待事件,使用这些信息可以识别是哪些等待事件造成了短暂的性能问题。
LoadProfile:描述了在抽样的会话活动中的负载分析.使用这部分信息可以识别造成短暂性能问题的服务,客户或sql命令类型。
TopSQL:描述了抽样会话活动中的顶级sql语句,使用这部分信息可以识别出造成短暂性能问题的高负载sql语句。Top SQL with Top Events(显示了在抽样会话活动中占总的等待事件很高百分比的sql语句);Top SQL with Top Row Sources(显示了在抽样会话活动中占很高百分比的sql语句和它们的详细执行计划信息;通过这部分信息可以识别出哪部分的sql执行消耗了大量的sql执行时间);Top SQL using literals(显示了在抽样会话活动中占很高百分比的使用literal值的SQL语句.可以重新检查这部分sql语句看是否能使用绑定变量来代替literal值)
Top PL/SQL Procedures:描述了在抽样会话活动中占很高百分比的pl/sql程序,例如存储过程。
Top Java Workload:描述了在抽样会话活动中占很高百分比的java资源。
Top Sessions:描述了会话正在等待的一个特定等待事件.使用这部分信息来识别在抽样会话活动中占很高百分比的会话,它们可能是造成短暂性能问题的原因。top sessions(显示了在抽样会话活动中占很高百分比的等待会话);top blocking sessions(显示了在抽样会话活动中占很高百分比的阻塞会话);Top Sessions running PQs(显示了哪些在抽样会话活动中占很高百分比的正处于等待的并行查询)
Top Objects/Files/Latches:描述了通常最消耗数据库资源的信息,如数据库对象、文件等。
Activity Over Time:对于长时间周期的ASH报告,分时段描述了关于活动和工作负载概要深层次的详细信息。
Oracle10g中推出了新的优化诊断工具:数据库自动诊断监视工具(Automatic DatabaseDiagnostic Monitor ADDM)和SQL优化建议工具(SQL Tuning Advisor STA)。可以通过ADDM以及STA辅助生成优化意见。
在测试环境取样AWR报告(awrrpt.sql),其中SQL ordered by Elapsed Time,SQL ordered by Gets、SQL ordered by Reads等部分的统计显示SQL_ID:062ukxu2gu0hh,总消耗资源,以及总执行时间均在前列。
select TSK_ID as Tsk from xxxx
再取样ASH报告,在Top SQL with Top Events以及Top SQL with Top Row Sources中可以发现该SQL中,TABLE ACCESS – FULL为主要的消耗事件,怀疑该SQL的执行方式为全表扫描。
获取单独SQL的AWR报告(awrsqrpt.sql),从中可以很明显地发现该SQL在采样时间段内的资源消耗情况以及执行计划等信息,从中可以验证之前我们猜测的执行方式为全表扫描是正确的。通过查询测试环境,该表数据量为150w,因此全表扫描的资源消耗较大。
按照正常的套路,我们可以通过建立索引来对该SQL进行优化。但接下来我们使用ADDM和STA,看看oracle会给我们什么建议。
生成该时段内的ADDM报告,在“Recommendation 2: SQL Tuning”中可以发现对该SQL在语句解析、执行次数以及资源消耗上的相关统计信息:同时有提示:
Full scan of TABLE "EV_QUEUE" with object ID 177255 consumed 32% of the database time spenton this SQL statement.(其中object ID 177255 对应的就是EV_QUEUE),且建议“Run SQL Tuning Advisor on the SELECT statement with SQL_ID “062ukxu2gu0hh".”
接下来我们再生成STA报告:
1)使用tuning advisor创建优化任务
DECLARE
my_task_name VARCHAR2 (30);
BEGIN
my_task_name :=
DBMS_SQLTUNE.CREATE_TUNING_TASK (
sql_id => '062ukxu2gu0hh',
plan_hash_value => '2251316543',
scope => 'COMPREHENSIVE',
time_limit => 7200,
task_name => 'tuning_task1',
description => 'Task to tune a query'
);
DBMS_SQLTUNE.EXECUTE_TUNING_TASK (task_name=> 'tuning_task1');
END;
/
2)查询优化任务的状态
SQL>select task_name,ADVISOR_NAME,STATUS from user_advisor_tasks;
TASK_NAME ADVISOR_NAME STATUS
-------------------------------------------------------------------------------------------------------
tuning_task1 SQL TuningAdvisor COMPLETED
3)设置输出格式,并查询报告
setlong 999999
set LONGCHUNKSIZE 999999
set serveroutput on size 999999
set linesize 200
select dbms_sqltune.report_tuning_task(' tuning_task1') from dual;
查询对应的STA报告,其中给出了两个建议:1-Statistics Finding(该处意见指向了另外一个数据库用户,可忽略)2-Index Finding (see explain plans section below),其中给出了创建索引的语句,以及前后执行计划的对比,可以发现在cost和time两列中,对应的消耗均有减少。
按照建议在测试环境进行了对比测试:
--未加索引
Elapsed:00:00:01.19
ExecutionPlan
----------------------------------------------------------
Planhash value: 2251316543
-----------------------------------------------------------------------------------
|Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 227 | 13837 (1)| 00:02:47 |
|* 1 | TABLEACCESS FULL| EV_QUEUE | 1 | 227 | 13837 (1)| 00:02:47 |
-----------------------------------------------------------------------------------
PredicateInformation (identified by operation id):
---------------------------------------------------
1 -filter("TSK_ID"='PTSK2016020501082877')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
51803 consistent gets
129 physical reads
3704 redo size
2301 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> create index i_ev_test on EV_QUEUE(TSK_ID) tablespace INDEX01;
Indexcreated.
Elapsed:00:00:00.05
ExecutionPlan
----------------------------------------------------------
Planhash value: 1159379706
---------------------------------------------------------------------------------------------
|Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 227 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EV_QUEUE | 1 | 227 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN |I_EV_TEST | 1 | | 3 (0)|00:00:01 |
---------------------------------------------------------------------------------------------
PredicateInformation (identified by operation id):
---------------------------------------------------
2 -access("PCSG_TSK_ID"='PTSK2016020501082877')
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
5 consistent gets
3 physical reads
0 redo size
2312 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
通过前后对比,资源消耗和用时都得到了优化,当然在日常的工作中也常常发现STA给出的建议也不一定都合理,仍然需要根据实际情况进行调整。