对于DBA日常的工作来说,AWR和ASH可能用的都比较多,但对于一个初学者来说,我们到底在什么场景下需要分别用到这两个报告呢?
首先来看AWR,AWR是Automatic Workload Repository的简写,也就是自动工作负载信息库,提供了一个时间段内整个系统的报表数据(默认间隔1小时收集一次),从这段描述就能看出,AWR更倾向于对数据库运行的大段时间内的总体情况的分析,比如我有一个系统,上午8点-10点是业务高峰期,我现在想看看该系统业务高峰期的总体运行情况,看看有没有优化空间,这时候AWR就非常有用,我们可以收集该时间段的AWR报告进行分析,从AWR中就可以很容易的看出该时间段内系统的繁忙程度、相关数据库资源的使用情况、最耗时的sql排行、最耗CPU的sql排行、top等待事件等等,如果发现有异常,oracle还提供了AWR报告的比对功能,可以把今天的和昨天同时段的AWR就行比较,进而帮助DBA更好的分析系统总体上有哪些大的变化,定位到变化之后再具体分析。总之AWR报告可以快速帮助DBA对一个数据库系统有一个比较全局的认识,但对于某些特别具体的问题,AWR可能就无能为力了,比如数据库出现了分钟级甚至秒级的卡顿,或者会话之间的阻塞关系等等。
- 接下来我们就来看看ASH的适用场景:
理清数据库一段时间内的阻塞关系
关于这一点,很明显AWR报告是做不到的,但是由于ASH的采样特点,以及利用采集到的信息(ASH视图相关列的使用),却可以很容易的做到这一点。
分析数据库中分钟级甚至秒级的卡顿
同样,同上一条。
查看等待事件的分布,主要都消耗在哪里了
关于这一点,AWR只能总体的告诉你某个时间段内都有哪些等待事件,总共等了多少次,再给你算一个平均等待时间,对于具体是哪个sql的等待都不知道;但通过ASH我们可以查出某条sql在执行的不同阶段都有哪些等待事件,或者哪些等待事件是由哪些sql引起的等等。
sql执行的历史时间信息
关于这一点,AWR也只能告诉你,过去某个时间段内,该sql总共执行了多少次,执行的总时间,消耗的总CPU,单次平均时间,单次平均CPU等等;但是通过ASH我们可以知道该sql在过去执行的过程中,最起码在采样点都干了些什么,都经历了哪些等待事件等信息。
统计每秒的并发数
通过ASH我们可以按时间精确到秒分组,再count就能知道每秒的并发数。关于并发数的统计我觉得还是很有用的,因为很多时候客户反馈我的系统突然变慢了,这时候很可能只是因为并发数突然上来了导致的。
查看PGA以及temp space的消耗
v$active_session_history视图的最后两列是PGA_ALLOCATED和TEMP_SPACE_ALLOCATED,官方文档解释如下:
image.png实时监控sql运行情况
以上说的ASH的适用场景,其实都是对ASH视图中不同列的使用,当然随着对不同列的使用以及各列组合方式的不同,那么ASH能做到的事可能更多,肯定不仅局限于此,所以这里就当抛砖引玉了,大家可以自行补充。
既然v$active_session_history视图能做到如此之多,那么就来过一遍这个视图中比较重要并且有用的一些列吧,一些字面意思就很清楚的就不一一列出了。
- SAMPLE_TIME:无需多言
IS_AWR_SAMPLE:我们知道ASH视图采样时间默认1秒,dba_hist_active_sess_history视图默认是10秒一采样,也就是每隔10秒将ASH视图中IS_AWR_SAMPLE值等于Y的那条记录持久化到dba_hist_active_sess_history视图中(持久化这个步骤并不是真的每10秒就进行一次,关于这一点上篇文章已做说明)。
image.png
- FORCE_MATCHING_SIGNATURE:这个不太好解释,不过官方文档中的说明已经很清楚了。
image.png
- TOP_LEVEL_SQL_ID:
很多时候面对包或者存储过程,我们看到的"sql_id"仅仅是包或者存储过程本身的"sql_id",但对于包以及存储过程里面到底包含了哪些sql是不知道的,这时候就可以利用这一列,查出包或者存储过程里的一系列sql_id。
- SQL_EXEC_ID:
唯一标识这条sql执行的这一次,有时候我们看到sql_id一样,但实际上是不知道执行了多少次的,这时候sql_id加上sql_exec_id就可以唯一标识具体的某一次执行。
- SEQ#
唯一标识某一次等待,如果相同的等待事件,多次采样seq#都一样,说明是同一次等待,就不太正常,因为正常情况下单次等待不会超过1秒(采样时间默认1秒),这个时候就需要特别关注。
image
- WAIT_TIME****:
如果采样时session处于on cpu状态,wait_time表示上一次等待的总时间,如果采样时session处于waiting状态,则wait_time=0;如果wait_time=0,那么就别再纠结这个值了,去看看session_state吧,或许更有用。
- TIME_WAITED:
如果session_state=waiting,那么time_waited就表示实际花费在等待上的时间,单位为微秒。
image.png
- BLOCKING_SESSION:
查询阻塞关系的关键列
image
- PGA_ALLOCATED:
如果有时候PGA不够了或者使用过高,可以关注此列看看到底是哪个session导致PGA使用量过高。
- TEMP_SPACE_ALLOCATED:
同理
image
接下来我们看看ASH视图的常见用法,对于常见用法,其实就是对ASH视图中的某些列的运用,当你了解的这些列都是什么含义之后,再来看常见用法就很简单了。注:下面这些sql的执行结果来源于某个客户那里收集的ASH信息。
- 查看某段时间内等待事件的汇总信息:
select event,count(*) from gv$active_session_history
where to_CHAR(sample_time, 'yyyymmdd hh24:mi:ss')>'20201013 20:00:00' and to_CHAR(sample_time, 'yyyymmdd hh24:mi:ss') <'20201013 22:00:00' and event is not null group by event
order by count(*) desc;
image
对于上面的查询结果,如果我们发现某一个等待事件比较可疑并想进一步关注这个等待事件,我们可以:
- 查看某个等待事件的具体分布情况:
select sql_id,event,count(*) from gv$active_session_history where to_CHAR(sample_time, 'yyyymmdd hh24:mi:ss')>'20201013 20:00:00' and to_CHAR(sample_time, 'yyyymmdd hh24:mi:ss')<'20201013 22:00:00' and event in ('enq: TX - row lock contention') group by sql_id,event order by count(*) desc; |
image
这时候就能定位到具体的sql_id了,之后我们就可以分析这条sql语句具体的在做什么,在业务逻辑上合不合理,是什么原因导致的等待以及他的执行计划是什么等等。
- 查看某个等待事件每小时出现的频率:
select to_char(sample_time, 'yyyy-mm-dd hh24') || ':00:00' TIME, session_id,count(*) from gv$active_session_history where event = 'enq: TX - row lock contention' group by to_char(sample_time, 'yyyy-mm-dd hh24') || ':00:00', session_id order by 1 asc;
image
有时候某些sql的运行是和业务场景息息相关的,比如有时候某条sql就是集中在某个时间点才会执行,这时候执行上面的sql就可以查看某一个等待事件,在哪个时间点出现的次数最多,以及涉及到session都有哪些,比如上图中的11点,以方便我们更有针对性的分析处理问题。
- 实时监控sql语句的运行(比如过去十分钟内sql语句的运行情
况):
col sql_text for a80
select substr(sq.sql_text,1,80) sql_text,a.* from (select sql_id, round(avg(cnt)) avg_time, max(cnt) max_time, count(*) execs
from (select sql_id, sql_exec_id, count(*) cnt from v$active_session_history where sample_time>sysdate-(10/(24*60)) and sql_id is not null and sql_exec_id is not null group by sql_id, sql_exec_id) group by sql_id order by 2 desc) a,v$sqlarea sq where a.sql_id=sq.sql_id(+);
image
我自己的环境太闲了,没什么sql在跑。
- 查看某个等待事件其阻塞者的分布:
select blocking_session,current_obj#,count(*) from gv$active_session_history where --to_char(sample_time,'yyyymmdd hh24mi') between '20201013 1624' and '20201013 1625' and event='enq: TX - index contention' group by blocking_session,current_obj# order by count(*) desc;
image
可以看到这个等待事件的阻塞者绝大部分都是2326和3971这两个session,既然已经定位到了阻塞者,那么我们继续来看看阻塞者的等待事件分布:
- 查看阻塞者等待事件的分布:
select event,count(*) from gv$active_session_history where --to_char(sample_time,'yyyymmdd hh24mi') between '20201013 1624' and '10101013 1625' and session_id=2326 group by event
order by count(*) desc;
image
可以看到其阻塞者基本都是在等gc buffer busy acquire这个等待事件。依靠以上一系列的sql我们就能很容易的理清楚各个session在等的等待事件以及各个session之间的阻塞关系,最终定位到阻塞源头。
- 查看某个session的等待事件分布:
select session_id sid,sql_id,event,count(*) from gv$active_session_history where to_CHAR(sample_time, 'yyyymmdd hh24:mi:ss')>'20201013 15:00:00' and to_CHAR(sample_time, 'yyyymmdd hh24:mi:ss')<'202010213 00:00:00' and session_id=2158 group by session_id,sql_id,event order by count(*) desc;
image
- ** session详情:(11g)**
select to_CHAR(sample_time, 'yyyymmdd hh24:mi:ss') t, session_id sid,blocking_session b, blocking_inst_id b_id, sql_exec_id,sql_exec_start, seq#,sql_id,event,p1,p2,p3, current_obj#,session_state,sql_plan_hash_value,sql_opname, sql_plan_operation,sql_plan_options,program,xid from gv$active_session_history where inst_id=1 order by 1;
上面的sql语句涉及的列是ASH视图中比较重要且常用的列,实际使用时可以根据实际情况自行取舍。
**最后案例就不说了,其实就是对上面这些sql语句的运用,还是那句话,ASH视图的使用远不止这些,根据不同的业务场景,用法可能千变万化,但归根结底不外乎就是对ASH视图中各个列的含义的理解并运用。**
网友评论