题记:本文对Statspack产生的报告进行简要说明,通过这些说明,希望读者能够对Statspack的数据来源以及报告解读有所了解。报告中的内容在任何数据库版本中都具有相同的含义,理解这些内容将有助于加深我们对于数据库的认知。
节选自《循序渐进Oracle:数据库管理、优化与备份恢复》
报表开头部分是数据库概要信息,包含数据库的一些基本信息(数据库名称、版本号、主机等信息)和采样信息、数据库的Cache信息等。
(1)首先是数据库名称、dbid等信息:
(2)接下来是数据库采样时段信息,这一部分记录了数据库采样的时间,以及采样点数,这部分信息对于report来说是十分重要。
任何统计数据都需要通过时间维度来衡量,离开了时间,任何数据都失去了意义。
(3)Cache信息,这一部分列举了数据库的内存分配信息,由于从Oracle 9i开始,主要SGA参数可以进行动态调整,所以此处的Cache信息来自采样结束时刻:
在数据库概要信息之后,报表中输出的是数据库的负载概要信息,这些信息分别通过每秒和每事务形式展现。通过这部分信息,报告讲数据库的整体运行状况快速展现出来。
通常每秒或每个事务的负载越高,那也就意味着数据库的压力越大,在不同的时段,数据库的负载可能不同,我们通过报告可以获得数据库负载变化的趋势,甚至绘制出按时间变化的负载曲线。
这部分信息来自v$sysstat视图收集的统计信息,Statspack将这部分信息定时收集记录在stats$sysstat字典表中,然后通过前后对比,得出在报告时段数据库的负载变化。例如这里的redo size就代表在起始采样点和结束采样点之间,数据库生成的redo大小。
1、SYSDIF函数
Statspack中的这些数据差值都是通过一个内部函数SYSDIF来获得的,这个函数的内容和算法可以从spcpkg.sql文件中找到,我们收录一下SYSDIF函数作为说明,其他相关数据的计算方法同样可以从该文件中找到,当大家试图深入了解或打算解除Statspack的相关疑惑时,可以尝试从这个文件入手。
SYSDIF函数是这样定义的:
这个函数很好懂,通过从stats$sysstat获得结束采样点时间的采样值(eval)和起始采样点时间的采样值(bval),两者相减就得出了采样阶段的数据变化。
2、Redo Size信息
在负载概要信息中首先出现的就是Redo Size信息,单位为Bytes:
对于这个采样,数据库每秒产生了大约234KB的Redo信息,每个事务平均产生了11KB左右的重做信息。
Redo Size的信息也可以从报告后面的Instance Activity Stats信息中获得:
这里的redo size和负载概要里面的redo size信息是一致的,只不过在概要信息里只显示了平均每秒产生的redo size以及平均每个事务产生的redo size。
由此来研究一下Oracle的计算方法,首先时间维度来自Statspack的采样时间:
41.27 mins = 20-Jun-03 23:29:27 - 20-Jun-0322:48:11 = 2476 s
所以每秒产生的Redo Size就是:
Redo Size s = round(593,925,812 2476,2) = 239873.11
概要信息还包括每秒的事务数量(Transactions/s),对于以上的示例,这个数值是20.86,那么这个数据是从何处得来的呢?首先要知道采样阶段数据库的总的事务数量,这个值等于用户提交的事务(user commits)和用户回滚的事务(user rollbacks)总和。
Statspack源码中这部分信息相关的参数这样定义:
urol :=SYSDIF('user rollbacks');
ucom :=SYSDIF('user commits');
tran := ucom + urol;
对于这个报告,从stats$sysstat表中可以得到采样期间的事务信息,这个信息也可以从report中的部分输出中得到:
根据这些信息可以计算出采样阶段总的事务数量:
Transactions = user commits + user rollbacks =31,910 + 19,740 = 51650
那么每秒的事务数量就可以很容易的计算得到:
Transactions s = round(51650 2476,2)=20.86
根据事务数量,平均每个事务产生的redo size也可以据此算出:
Redo Size per Trans = round(593,925,812/ 51650) = 11499.05
这也就是负载概要信息的第一个数据的由来。同样每秒的事务数量也是衡量数据库负载的重要指标,在本例中每秒的事务数量是20.86个,至于这个事务数量是高还是低,还和系统的CPU数量有系,Statspack不包含系统信息,所以无法对系统资源进行评估,这是Statspack的一个欠缺之处。在Oracle 10g的AWR中则包含了这部分信息。
继续前面的讨论,那么这个Redo Size具体来自何处呢?我们再来进一步分析一下。
我们知道stats$sysstat中的统计数据来自v$sysstat,而v$sysstat中的数据来自数据库中各session的累积,各session的实时信息记录在v$sesstat视图中(对于当前session的统计信息也可以从v$mystat视图中获得)。
下面来执行一个数据库CTAS创建操作,看看数据库的redo变化。首先记录测试之前的session redo信息,再记录v$sysstat的系统数据:
接下来执行一个CTAS(CreateTable As Select)操作:
SQL> create table eygle as select * fromdba_users;
Table created.
在session级和系统级再来分别看一下Redo Size的变化:
对比一下,Session的Redo Size完全累计记入v$sysstat中:
SQL> select 58876 -6404,9953536 -9901064 fromdual;
58876-6404 9953536-9901064
---------- ---------------
52472 52472
这就是这些信息的来源以及缘起。最后归结到根本,Redo Size又是什么呢?
Redo Size就是数据库操作产生的日志量(Redo Log)的大小,单位为Byte,如果单位时间内数据库产生的Redo非常多,那么就意味着LGWR要非常频繁地将Redo Log Buffer中的数据写出到Redo Log File上来,而这又意味着Redo Log File的I/O写入将会很频繁,也就可能导致I/O竞争和忙碌,同时Log Switch可能增加,也就会导致检查点的发生,从而DBWR要被唤醒,执行脏数据的写出,CKPT进程也要开始它的工作;如果日志过多,在归档模式下,归档日志可能就会非常频繁的产生,这又意味着I/O竞争和空间耗用;如果日志切换更快,那么数据库就可能出现“检查点未完成”的错误提示,日志组可能全部处于Active状态,如果此时数据库崩溃,那么数据库可能会经历更为漫长的恢复过程。
如果……如果……这里的“如果”,可以继续问下去,Oracle数据库就是这样一个牵一发而动全身的系统,从一条线开始,我们可以深入地走很远很远。
3、逻辑读信息
负载概要信息中接下来显示的逻辑读(Logical Reads)信息也非常重要:
Logical reads: 506,974.15 24,303.35
逻辑读(LogicalReads)是指以任何模式进行数据块读取的逻辑读请求次数。逻辑读是一个派生的统计数据,其计算公式如下:
Logical Reads = db block gets + consistent gets
从v$sysstat视图的统计数据,可以清楚地看到这一关系(以下是一个Oracle 10g产品库的输出):
逻辑读代表了数据库读取数据的繁忙程度,如果数据库每秒都要进行大量的逻辑读,那么不管是I/O还是buffer的竞争都可能会非常的激烈。我们曾经反复提到过,有效的降低逻辑读是SQL优化的基本原则之一,对于业务非常繁忙的系统,甚至每一个逻辑读都需要进行精心调节。
对于这个报告,相关数据同样可以从后面的详细信息中找到(对于长时间运行的数据库,由于取整或计算的关系,数据可能会略有偏差):
根据逻辑读,结合物理读信息,可以进一步获得数据库系统的其他概况:
从以上的数据可以看到,数据库每秒的物理读仅约955个,也就是说仅有0.2%左右的逻辑读导致了物理读取,这个比例是相当理想的。如果物理读的比例过高,那么系统的性能将会出现问题。
4、其他信息
负载概要信息中还包含一系列的重要信息。Block changes代表采样阶段Block修改信息:
Blockchanges: 1,881.28 90.18
Blockchanges数据来自v$sysstat表中的db block changes数据:
db block changes 4,658,038 1,881.3 90.2
SQL解析信息:
Parses: 1,098.00 52.64
Hard parses: 32.42 1.55
Parses代表数据库在采样阶段的总的分析次数,Hard Parses代表硬解析的数量,一个优化良好的数据库应该具有很低的硬解析,硬解析是非常消耗资源的数据库活动。硬解析频繁的数据库通常是因为没有很好的使用绑定变量,或者共享内存设置的不够合理。
这两个数据来自report中Instance Activity Stats部分:
% Blocks changed per Read代表逻辑读导致的Block变更百分比,对于这个报告,有99%以上的逻辑读是只读操作,仅有0.37%的逻辑读设计数据块变更:
% Blocks changedper Read: 0.37 Recursive Call %: 1.14
这个计算数值来自于以上的两个数值计算:
% Block changes Logical reads =round(1881.28 / 506,974.15,4) *100%= 0.37
这个数值越高说明数据库的数据块变更越频繁,频繁的数据变更会给数据库带来一系列的压力及性能影响。
Rollback pertransaction代表平均事务回滚率:
Rollbackper transaction %: 38.22 Rows per Sort: 11.83
回滚是非常昂贵的数据库操作,如果回滚率过高,可能说明你的数据库经历了太多的无效操作,过多的回滚可能还会带来Undo Block的竞争。平均事务回滚率计算公式如下:
Round(User rollbacks / (user commits + user rollbacks) ,4)* 100%
对于本例,Rollback per transaction % = Round(19740/ (31910 + 19740),4)*100% = 38.22,这个回滚率高达38.22%是不正常的,我们应该检查应用系统为什么经历了如此之多的无效事务。
关于回滚率的计算,还应该了解user rollbacks和transaction rollbacks的区别,在数据库中,user rollbacks的数量通常会比transaction rollbacks偏大:
这是因为即使不执行事务,仅发出rollback操作,user rollbacks统计信息也会增长,而transaction rollbacks则仅会在事务回滚时增长:
基于这个不同,回滚率更为精确的计算方式应该为:
Round(Transaction rollbacks / (user commits +transaction rollbacks) ,4)* 100%
通常的OLTP数据库,事务提交居多,回滚极少,所以可以忽略这个误差的影响;如果这两者差距很大,就应该通过考察统计数据来确定是否回滚率是否真的偏高。
总之,这一部分显示的信息都是非常重要的,这些信息快速的将数据的运行状况展示出来,我们通过这些信息可以对数据库运行状况快速形成一个整体的认识。
下期继续分享Statspack报告的全面解读之实例效率、响应时间及主机信息等。
加入"云和恩墨大讲堂"微信群,参与讨论学习
搜索 盖国强(Eygle) :eyygle,或者扫描下面二维码,备注:云和恩墨大讲堂,即可入群。每周与千人共享免费技术分享,与讲师在线讨论。