oracle实时性能诊断
最近在工作中遇到一些ORACLE性能问题,用AWR和Statspack报告来做分析的话,发现问题总觉得有些滞后性,而且是对数据库整体情况的评价,不够及时,所以又把盖国强的《ORACLE 数据库性能优化》拿出来重新看了一遍大师们解决问题的案例,又学到些新知识,总结一下:
一、AWR和STATSPACK虽然也能诊断数据库的性能,但只能取一段时间的起始和结束时间分别取快照,然后再做分析,而且取到的报告还必须和正常情况下的报告做对比才容易发现问题。而使用动态性能视图能够在事件发现的当时发现问题。
二、出现性能问题时,用户的反应及描述一般都是“数据库好慢”,而作为计算机专业人员来说,这个术语应该叫做“响应时间”太长。而响应时间=服务时间+等待时间。
在数据库中就叫做DB TIME=DB CPU+ WAIT TIME,所以我们就必须从DB CPU和WAIT TIME两方面入手来找原因,而出现问题时一般是因为WAIT TIME变长引起的,所以现在的性能诊断方面基本上都是基于“等待事件”的。
三、而出现性能问题时,作为DBA,首先需要做的就是冷静分析问题,这里有几个可以遵循的一般步骤:
首先:以操作系统作为切入点。因为数据库只是运行于操作系统这个“系统软件”之上的众多“应用软件”中的一个,“应用软件”变慢,我们首先当然要看系统的资源占用情况,CPU、内存、IO,确定问题出现在哪一块上面。就像我们在Windows下,如果系统变得很慢,我们一般都会看看“任务管理器”,看CPU或CPU是不是被占用完了。而LINUX下是以线程来管理资源的,所以资源的占用情况会更细。下面我会列出一些常用的操作系统命令。
其次:找出问题SID。通过上一步确定大方向之后,如果是单个的线程消耗大量资源,则根据PID(进程号)找出其对应的SESSION的SQL语句以及SQL语句存在的问题,如果是多个线程,则要根据多个会话当前的等待事件的统计信息来确定是什么等待事件影响了性能。
然后:深入等待事件。根据不同的等待事件再深入查找该等待事件的详细信息,找到问题的根源。
最后:采取措施。找到根源后对症下药。不同的等待事件的处理方法不同,如果通过"db file scatted read"找出某个表未走索引,则建立相关索引,如果session异常则进行alter system kill session 'sid,serial#',等等。
下面列出一些常用的命令,以备工作之需:
1. 操作系统命令。
1.1 vmstat 3 10
1.2 top
1.3 free
1.4 ps -ef
1.5 sar
1.6 iostat
2. SQL脚本。
2.1 目前正在等待的等待事件的等待次数
--seswa.sql select event "Wait Event", sum(seconds_in_wait) "Waited So Far(sec)", count(sid) "Num Sess Waiting" from v$session_wait group by event order by 3 desc;
2.2 从整个系统考虑,找到从系统启动以来最主要的等待事件是什么?
SQL>@syssum.sql
--syssum.sql set linesize 200 col "Wait Event" for a45 select EVENT "Wait Event",TIME_WAITED "Time Waited", round(TIME_WAITED/(SELECT SUM(TIME_WAITED) FROM v$system_event),2) "%Time waited", TOTAL_WAITS "Waits", round(TOTAL_WAITS/(SELECT SUM(TOTAL_WAITS) FROM V$system_event),2) "%Waited" from v$system_event order by 3 desc;
2.3. 在应用执行期间,最主要的等待事件是什么?
SQL>@cr_base.sql
--cr_base.sql create table sys_b( event varchar2(64), time_waited number, total_waits number);
create table sys_e( event varchar2(64), time_waited number, total_waits number);
SQL>@in_base.sql
--in_base.sql insert into sys_b select event,time_waited,total_waits from v$system_event;
--执行用户应用操作一段时间后.....
SQL>@re_base.sql
--re_base.sql insert into sys_e select event,time_waited,total_waits from v$system_event; create table sys_dif as select e.event ,e.time_waited-b.time_waited TIME_WAITED, e.total_waits-b.total_waits TOTAL_WAITS from sys_b b,sys_e e where b.event=e.event; select event "Wait Event",time_waited "Time Waited", time_waited/(select sum(time_waited) from sys_dif) "%Time waited", total_waits "Waits", total_waits /(select sum(total_waits) from sys_dif) "%Waited" from sys_dif order by 3 desc; drop table sys_dif; drop table sys_b; drop table sys_e;
2.4 查询产生该等待事件最多的哪些会话?
SQL>@seswt.sql event_name
--seswt.sql select sid,event "Wait Event",state "Wait Stat", wait_time "W'd So Far(secs)", seconds_in_wait "Time W'd (secs)" from v$session_wait where event like '&event_name' order by 5 desc;
2.5 找出资源消耗情况最大的SID以及Sql Address
SQL>@sqlst.sql
--sqlst.sql select cpu.sid "SID",cpu.username "USER Name",cpu.value "CPU(sec)", reads.value "IO Read(k)",writes.value "IO Write(k)",cpu.sql_address from (select a.sid sid,a.sql_address,a.username username,b.name,c.value value,a.serial# serial# from v$session a,v$statname b,v$sesstat c where a.sid=c.sid and b.statistic#=c.statistic# and b.name='CPU used by this session') cpu, (select a.sid,a.username,b.name,c.value value from v$session a,v$statname b ,v$sesstat c where a.sid=c.sid and b.statistic#=c.statistic# and b.name='physical reads') reads, (select a.sid,a.username,b.name,c.value value from v$session a,v$statname b ,v$sesstat c where a.sid=c.sid and b.statistic#=c.statistic# and b.name='physical writes') writes where cpu.sid=reads.sid and reads.sid=writes.sid and cpu.username is not null order by cpu.value desc;
2.6 通过Sql Address找SQL语句
SQL>@sqls2.sql 2168CBB8
--sqls2.sql select sql_text "SQL Statement Text" from v$sqlarea where ADDRESS='&sql_address';
2.7 通过SID找出SQL语句:
--getsqlbysid SELECT sql_text FROM v$sqltext a WHERE a.hash_value = (SELECT sql_hash_value FROM v$session b WHERE b.sid = '&SID') ORDER BY piece ASC
2.8 通过PID找出SQL语句:
SELECT sql_text, spid, v$session.program, process FROM v$sqlarea, v$session, v$process WHERE v$sqlarea.address = v$session.sql_address AND v$sqlarea.hash_value = V$session.sql_hash_value AND v$session.paddr = v$process.addr AND v$process.spid IN (&PID);
2.9 查找哪些语句引起的等待,按照最消耗资源的顺序排列显示
SQL>@sqls1.sql 1000 1000
--sqls1.sql select * from (select address "Stmt Addr", disk_reads "Disk RDS", buffer_gets "Buff Gets", sorts "Sorts", executions "Runs", loads "Body Loads" from v$sqlarea where disk_reads > &A order by disk_reads ) where rownum < &B;