一个数据库会话只有3种状态
idle 不做任何事情- 等待接受工作
processing 正在CPU上做一些有用的
waitting 等待一些类似来自于disk上的block或等待锁释放
如果会话正在等待有些资源,比如块或锁,它已经停止处理了。除非它得到该资源,会话会持续等待。当它得到该资源时,它进行一些处理,之后接着移动到下一个它所需的资源,等待该资源可用,之后开始处理,这个循环直到会话无活可做。如果会话经常等待,会话看起来运行很慢,但不是真慢,它只是遵循运行,停止,再次运行,再次停止等方式。
v$session会话的状态没有idle,idle的会话状态仍然是waiting,只不过等待的事件是
SQL*Net message fromclient
rdbms ipc message
SQL*Net message fromclient等待事件一般说明会话idle,如果网络很慢,也会出现这种等待,但会话不是idle的。会话本身也不知道它是真正的idle还是正在发出的指令网络太慢或卡住。
行级锁不仅是性能问题的唯一原因,另一个主要原因是磁盘I/O竞争。当会话从磁盘的数据文件获得数据到buffer cache时,它必须等待直到磁盘发送数据。这个等待会在v$session的event列显示“dbfile sequential read” (for index scans) or “db file scattered read” (forfull-table scans)
当你看到这种事件时,会话正在等待来自于磁盘I/O完成。要使得会话更快运行,必须减少等待周期。有好几种方法来降低等待:
减少SQL语句获得数据块的数量。检查SQL语句当它应该使用索引时是否在执行全表扫描,是否使用了错误的索引,或是否可以重写来减少获取的数据量。
将SQL语句使用的表放到一个性能更好的存储上。考虑增加buffer cache来检查是否扩容容量会容纳额外的数据块,因此减少了I/O和等待。
对I/O系统调优来使得返回数据更块。
通过减少SQL语句获取数据块的数量-永远是立即见效的。
当你想要减少数据块的访问数量时,查看SQL语句可能会发现多个表关联。如何确定哪一个表导致了等待?
要找到导致等待的表,还要使用v$session视图。该视图的P1(file_#)和P2(block_#)列提供了会话等待的段信息。
select SID, state, event, p1, p2
from v$session
where username = 'ARUP';
SID STATE EVENT P1 P2
———— ——————— ————————————
2201 WAITING db file sequential read 5 3011
select owner, segment_name
from dba_extents
where file_id = 5
and 3011 between block_id
and block_id + blocks;
OWNER SEGMENT_NAME
—————— —————————————
ARUP T1
检查会话是working还是waiting。确定等待的资源,等待的时间
对比等待周期内会话多久之前执行了SQL
如果是锁竞争导致的等待,找出持有锁的会话并得到会话的详细信息。
找出会话正在执行的SQL语句。如果会话正在等待I/O,找出等待的数据段(表,索引,等)
如果一个会话在过去有段时间出现性能问题,那么可以尝试查看v$session_event
set lines 120 trimspool on
col event head "Waited for" format a30
col total_waits head "Total|Waits" format 999,999
col tw_ms head "Waited|for (ms)" format 999,999.99
col aw_ms head "Average|Wait (ms)" format 999,999.99
col mw_ms head "Max|Wait (ms)" format 999,999.99
select event, total_waits, time_waited*10 tw_ms,
average_wait*10 aw_ms, max_wait*10 mw_ms
from v$session_event
where sid = 37
/
Total Waited Average Max
Waited for Waits for (ms) Wait (ms) Wait (ms)
—————————————————————————— ———————————
Disk file operations I/O 8 .00 .10 .00
KSV master wait 2 350.00 173.20 340.00
os thread startup 1 20.00 19.30 20.00
db file sequential read 5 160.00 32.10 70.00
direct path read 1,521 51,010.00 33.50 120.00
direct path read temp 463,035 513,810.00 1.10 120.00
direct path write temp 20 370.00 18.70 50.00
resmgr:cpu quantum 21 520.00 24.60 110.00
utl_file I/O 8 .00 .00 .00
SQL*Net message to client 20 .00 .00 .00
SQL*Net message from client 20 9,620.00 481.20 9,619.00
kfk: async disk IO 904,818 3,050.00 .00 .00
events in waitclass Other 35 20.00 .70 20.00
在这个案例中,你应该注意导致会话大部分时间等待的事件。可以看到37号会话等待了513,810us,或8.5分钟多,等待“direct path read temp”事件。每次平均等待1.1ms,因此减少该事件的时间,就能降低该会话的整体等待时间。查看会话时间历史是你能找出会话延迟的最大嫌疑。
为何存在“Max Wait (ms)”?那是因为平均等待时间并不能告诉所有的情况。比如会话等待20次“SQL*Net message from client” event,但平均等待时间是481ms。但是这不意味着20次事件的发生每次等待都是481ms,而是大部分每次都等待了很短时间,只有1次等待时间很长。“Max Wait (ms)”显示会话一次等待该事件的最长时间。该值是9619ms,因为总数是9620ms,可以认为是一次意外的大的等待,该事件不应被关注。换句话说,当你看到maximumtime接近average time,你就能推测该事件每次发生都等待了相同的时间。这种情况下,减少该事件的时间可能会应用到每次等待上,进而整体减少总的等待时间。
虽然V$SESSION_EVENT视图显示了会话之前的等待,但并不显示何时发生的。V$ACTIVE_SESSION_HISTORY会话可以看到。
统计数据
虽然等待事件极大地帮助了如何理解会话所经历的缓慢。但并不显示另一个重要会话属性:资源的使用,比如CPU,I/O和内存。占用资源的会话剥夺了其他会话对该资源的使用,因此导致了性能问题。当问题的根源是该会话消耗了太多的CPU,你应该查找资源消耗-而不是会话的等待事件。v$sesstat视图能够解决,有3列:
- sid
- statistic# 捕获的统计数据的ID (可以关联v$statname的name列找出统计数据名称)
- value 统计数据的值
CPU尖峰
假设有好几个用户抱怨性能很差,UNIX管理员说CPU和内存都消耗很高,大部分是DB的进程。
top找出顶级进程
ps -ef 查看是否是oracle进程
根据进程号找到会话SID
select sid
from v$session s, v$process p
where p.spid = 5946
and s.paddr = p.addr;
一旦得到会话号,就能得知会话的用户,连接的主机,执行的SQL等
select sql_fulltext
from v$sql l, v$session s
where s.sid = 37
and l.sql_id = s.sql_id;
现在是否应该立即kill会话,不是,首先要了解CPU消耗是最近的或会话是否一开始就消耗这么大。要找出会话消耗的CPU,执行下面的查询
select s.value
from v$sesstat s, v$statname n
where s.sid = 37
and n.statistic# = s.statistic#
and n.name = 'CPU used by this session';
VALUE
—————
47379
输出显示该会话自启动时消耗的CPU周期。假设会话已经运行了2分钟,CPU消耗确实很高,看起来该会话一直都在消耗CPU。再检查会话的其他信息,类比正在执行的SQL,找出根源:你会知道会话正在执行多表关联,消耗了大量CPU。这时你可能决定kill会话或决定让它继续运行。
所有统计数据
再查一次会话37的CPU消耗,发现值变为69724. 注意该值比上一次CPU使用查询47379要更大。这是因为统计数据随着时间增大。首次查看CPU使用,我们根据语句判断CPU消耗过大是由于多表笛卡尔集,但是是否能够证明呢,答案是肯定的。
下面查看会话37的所有统计数据
select name, value
from v$sesstat s, v$statname n
where sid = 37
and n.statistic# = s.statistic#
order by value desc
/
NAME VALUE
———————————————————————————————
table scan rows gotten 1.0236E+10
session logical reads 25898547
consistent gets 25898543
table scan blocks gotten 25325165
session pga memory max 21250020
session pga memory 21250020
session uga memory max 20156552
session uga memory 20156552
bytes sent via SQL*Net to client 878760
recursive calls 576848
opened cursors cumulative 143367
parse count (total) 143292
parse count (hard) 143118
table scans (short tables) 143086
sql area evicted 141996
DB time 70007
CPU used by this session 69724
从上面的输出看出表扫描获得的行数量是1.0236E+10,大约10亿行。对于一个会话来说在2分钟访问10亿行确实是一个很大的数字。Consistent gets统计数据的值是25898543-大约从buffer cache获得2500万个块读。大量的Buffer gets会占用很好的CPU。
另一个CPU消耗的原因是SQL语句的解析。parse count (total)统计数据,值为143292,这说明会话必须在2分钟内解析-而不只是执行-SQL语句很多次,这很异常。检查会话执行的SQL语句,可以看到它创建了不同的字面SQL语句。每个字面SQL语句都需要被解析。因此通过上面的输出,该会话CPU使用很高有2个原因:大量buffer gets和大量的解析。
同时还有2组统计数据 “session pga memory max” and “session uga memory max,”表示该会话消耗的总内存。很高的数字解释了高内存占用。如果你想要减少服务器CPU和内存消耗,你需要确保会话对这些资源消耗更少一点,通过修改会话执行的SQL语句来实现。
Redo尖峰
偶然你可能有一个性能问题,它不像在OS级别CPU和内存消耗很清晰。其中一种情况是DB实例生成的redo,日志切换很快,redo创建的速度和归档日志文件的个数持续增长。这可能是文件系统(或ASM磁盘组)总体I/O增加导致的,导致一个系统范围的性能问题。要减缓这种类型的问题,你需要定位导致redo大量产生的会话,但是查看OS度量不会提供任何线索。这种情况下,你需要查看对大部分负载负责的会话:产生最大redo的会话。查看v$sesstat能轻松地获得这个信息。
select sid, value
from v$sesstat s, v$statname n
where n.statistic# = s.statistic#
and n.name = 'redo size'
order by value desc;
SID VALUE
———— ————————
13 11982752
10 3372240
17 964912
26 571324
可以清楚地看到会话13产生了大部分redo,接着是会话10等。
接下来你查看会话13正在执行的SQL语句或上一次执行的SQL语句,定位产生大量redo数据的SQL语句。
其他统计数据
上面展示了使用redosize, session pga memorymax, and CPU statistics used by a session统计数据的使用。下面是v$sesstat视图内一些其他有用的统计数据
- physical reads : 从磁盘获得数据块的数量
- db block changes: 会话修改数据块的数量
- bytes sent via SQL *Net to client: 通过网络接受来自于客户端的字节,用语确定来自于客户端的网络流量。
虽然无法对每个统计数据一一解释,希望你能使用这些统计数据来查看会话对不同资源的使用并聚焦性能。(注意还有一个v$sysstat显示整个实例的统计数据)
总结:通过上面的内容,你学习到2个很重要的性能调整信息的重要来源:
会话经历的等待事件历史-v$session_event
会话消耗的资源-v$sesstat.
通过历史,你将能找出为何会话在过去曾经等待并且等待多久。
资源统计数据显示了会话对不同资源的消耗-CPU, 内存和redo。