10G的性能分析新特性
当数据库发生了性能问题时,如何去定位?比较常用的方法是采用一个既定的模式:解决诸如“是不是同一问题的再现?”、“是否在某一特殊时间段发生?”、“两个问题之间是否存在联系?”等问题,这样通常能得到一个比较好的诊断结果。作为一个DBA,你可能使用一个第三方或者自己开发的工具来收集数据库运行期间的精细统计数据,并从中得到性能度量数据。你需要将这些发生问题时的度量数据与当前数据进行比较。重现以前的时间能使现在的问题变得明朗。因此,持续的收集相关统计数据对于性能分析来说十分重要。在某些情况下,在解决收集统计数据这方面的问题上有自己内置的工具——statspack。尽管在某些情况下的作用非常大,但它缺乏解决性能问题所必须的健壮性。提供了一个标志性的改进特性:自动工作量存储(Automatic Workload Repository AWR)。AWR是随着数据库一起被安装的,它不仅能收集统计数据,还能从统计数据中分析出度量数据。
通过运行$ORACLE_HOME/rdbms/admin目录下的awrrpt.sql脚本可以生产AWR从统计和度量数据中分析报告。这个分析报告最能体现出AWR的性能分析能力。这个脚本看起来很像statspack,它会列出所有可用的AWR快照并要求输入两个特定的快照编号作为一个间隔段。它能产生两种类型的输出:文本格式(除了AWR统计信息外和statspack报告基本类似)和默认的格式(通过超连接等方式来提供一个友好的界面)。下面来运行以下这个脚本,对它产生的分析报告及AWR的性能分析能力做一个认识。
AWR的使用
首先来了解一下AWR是如何设计的,并了解一下它的构造。基本上来说,AWR应该是一个Oracle用来收集性能相关统计数据并从中得出性能度量数据来追踪潜在问题的内置工具。和statspack不一样,AWR的快照信息是由一个新的后台进程MMON及其线程来每隔一个小时自动收集的。为了节省空间,这些收集的数据会在7天后自动清除。快照收集的频率和保留时间都是可以被用户修改的。可以通过以下脚本查看当前的设置:
这个结果表明当前的快照是每隔一个小时收集一次,并且会被保留7天。要改变这个设置,比如需要设置成每隔半小时收集一次,并且只保留3天,可以使用以下语句(参数的单位都是分):SQL> select snap_interval, retention from dba_hist_wr_control; SNAP_INTERVAL RETENTION ------------------- ------------------- +00000 01:00:00.0 +00007 00:00:00.0
SQL> begin 2 dbms_workload_repository.modify_snapshot_settings ( 3 interval => 30, 4 retention => 3*24*60 5 ); 6 end; SQL> select snap_interval, retention from dba_hist_wr_control; SNAP_INTERVAL RETENTION ------------------- ------------------- +00000 00:30:00.0 +00003 00:00:00.0
AWR使用多个表来存储收集的统计数据,它们都被放置在SYS这个方案中,存储在一个新的特殊表空间SYSAUX上,并且以WRM$_*和WRH$_*的格式存储。前面一种格式的表存储诸如数据库检查和采集的快照等元数据信息,而后面一种格式的表存储了实际收集的统计数据(M表示“Metadata元数据”,H表示“Historical历史”)。另外还有多个以“DBA_HIST_”为前缀,由这些表构造出的视图。你可以利用这些视图写出自己的性能分析工具。这些视图的命名与它相关的表直接相关。比如,视图DBA_HIST_SYSMETRIC_SUMMAY是以表WRH$_SYSMETRIC_SMMURY为基础构造的。
AWR的历史信息表捕捉了比statspack多得多的信息,包括表空间的使用情况、文件系统的使用情况、甚至操作系统的统计信息。可以用以下语句从数据字典中得到这些表的完整列表:
select view_name from user_views where view_name like 'DBA\_HIST\_%' escape '\';
视图DBA_HIST_METRIC_NAME定义了AWR收集的重要度量数据、它们所属哪个组以及他们实在哪个单元被收集的。下面是一条记录例子:
DBID : 4133493568 GROUP_ID : 2 GROUP_NAME : System Metrics Long Duration METRIC_ID : 2075 METRIC_NAME : CPU Usage Per Sec METRIC_UNIT : CentiSeconds Per Second
这个数据显示了一个隶属于 “系统长期度量数据”的度量数据组中的“每秒的厘秒数”单元的“CPU每秒使用情况”的度量项。这条记录可以和其他表如“DBA_HIST_SYSMETRIC_SUMMARY”联合查询来起作用:
SQL> select begin_time, intsize, num_interval, minval, maxval, average, standard_deviation sd from dba_hist_sysmetric_summary where metric_id = 2075; BEGIN INTSIZE NUM_INTERVAL MINVAL MAXVAL AVERAGE SD ----- ---------- ------------ ------- ------- -------- ---------- 11:39 179916 30 0 33 3 9.81553548 11:09 180023 30 21 35 28 5.91543912 … …
这显示的是以厘秒为单位的CPU消耗时间。在分析数据中的标准偏差(Standard Deviation SD)可以帮助我们来确定平均数据图是否反映实际工组负荷。在第一条记录中,平均值是每秒钟CPU消耗3厘秒,而标准偏差是9.81,这说明平均为3并没有反映出实际工作负荷。在第二条记录中,平均值是28,而标准偏差是5.9,所以这条记录更具代表性。这种类型的信息有助于帮助理解在性能度量中的几个环境参数的作用。
使用这些统计数据
上面我们了解了AWR是如何收集统计数据的,下面就来了解以下如何利用这些数据。大多数性能问题并非孤立的,但是也不要相信哪些可以找出问题的最终根源的流言。让我们来做一个典型的调优练习:你发现系统变得很慢,决定检查一下等待事件。通过检查发现,“缓存忙等待(buffer busy wait)”非常高。如何解决这个问题呢?存在几种可能:可能是索引的单一增长引起的;某张表饱和了,需要立即转载一个数据块到内存中;以及其他的原因引起的。在任何情况下,你都需要先定位出发生问题的段。如果它是一个索引段,你可以决定是否重建索引、把索引改为相反键索引、或者将索引转换为在Oracle 10G特有的哈希分区索引。如果是一张表,可以考虑修改表的存储参数使它密度降低,或者将它转移到一个自动段空间管理的表空间上去。你的这些计划、措施一般都是系统的,并且是基于你对各种事件的了解和你在处理这些问题所积累的经验。想向一下,如果这些事情是由机器驱动来完成——这个驱动能捕捉度量数据并且在基于预先定义的逻辑能演绎出可能的计划、措施,那么你的工作不是能变得很轻松吗?
现在Oracle 10G就提供了这样的驱动,它就是自动数据库诊断监视器(Automatic Database Diagnostic Monitor ADDM)。ADDM使用AWR收集的数据来达到那样的效果。在上述的例子中,ADDM能够发现发生了buffer busy waits,找出适当的数据来检查在哪个段上面发生的,计算出它的本来数据和混合数据,并最终为DBA提供解决办法。每当AWR收集了一个快照数据,ADDM就会检查这些度量数据,并产生出相应建议。因此,你就拥有了一个全天候工作的机器人DBA来为你分析数据、提前为你给出建议,让你由更多的时间来关注战略问题。通过使用新的10G企业管理器平台——DB Home——可以查看ADDM的建议和AWR存储的数据。你可以从管理界面的导航器上查看AWR的报告、负荷数据以及快照信息。将来可以安装更多组件来在更多细节上来检查ADDM。
你还可以指定在特定条件下产生告警信息。这些告警,如服务器产生的告警(Server Generated Alerts),会被推入一个高级队列。在任意一个客户端上可以监听这个队列。一种客户端就是10G企业管理器,在上面可以显著的显示出告警信息。
时间模型
当你遇到一个性能问题时,首先想起降低哪个响应时间呢?你当然希望能消除或降低引起问题的最终因素的时间。但是你怎么才能知道时间被消耗在哪呢——不是等待,而是实际的工作时间?
Oracle 10G介绍了使用时间模型来通过不同途径定位时间消耗。整个系统的时间消耗被记录在视图V$SYS_TIME_MODEL中。下面是一个对这个视图查询的结果:
STAT_NAME VALUE ------------------------------------- -------------- DB time 58211645 DB CPU 54500000 background cpu time 254490000 sequence load elapsed time 0 parse time elapsed 1867816 hard parse elapsed time 1758922 sql execute elapsed time 57632352 connection management call elapsed time 288819 failed parse elapsed time 50794 hard parse (sharing criteria) elapsed time 220345 hard parse (bind mismatch) elapsed time 5040 PL/SQL execution elapsed time 197792 inbound PL/SQL rpc elapsed time 0 PL/SQL compilation elapsed time 593992 Java execution elapsed time 0 bind/define call elapsed time 0
注意DB Time这个统计项,它表明了自从实例启动后数据库消耗的时间。重新运行查询这个视图的语句,数据库消耗时间的数据将和之前不同。通过一轮调优,再作同样的分析,可以看出调优后的DB Time的改变,通过和第一的数据比较发生的变化,可以检查调优对于数据库时间产生的影响。除了数据库时间,视图V$SYS_TIME_MODEL还能显示其他很多统计数据,如消耗在不同类型的语句分析(Parsing)上的时间,甚至PL/SQL的编译时间。
这个视图显示的整个系统的时间模型。但是你可能对更细粒度上的视图感兴趣:会话级的时间模型。视图V$SESS_TIME_MODEL能显示在会话级捕捉到的时间统计数据。这些数据统计的是当前的会话,包括所有的活动的和不活动的都可见。多出的字段SID表明了所统计的会话的SID。
在Oracle的以前版本,这些数据根本无法获取到,需要用户从各种其他数据中猜测出来。在Oracle 10g中,获取这些数据简直是小菜一碟。
视图V$SESSION在oracle 10G中被增强了,其中最有价值的一项增强就是包括了等待时间和他们持续的时间,而不需要通过V$SESSION_WAIT来查看了。然而,因为这个视图很少反映出真实的时间值,所以一些重要信息就丢失了。例如,如果你从这个视图中查询看是否存在某个会话在等待某个非空闲的事件,而如果这个事件的数据存在问题,你将无法找到你想要的东西,因为等待事件必须依赖于你所查询到的时间数据。Oracle 10G的另一个特性活动会话历史(Active Session History ASH)和AWR类似,将会话的性能统计数据存储在一个缓存中以便于将来的分析。但是,和AWR不一样的是,这些数据的存储并非永久的存储在表当中,而是存在内存当中,可以通过视图V$ACTIVE_SESSION_HISTORY来查到。这些数据每秒中被收集一次,并且只有哪些活动的会话才会被收集。随着时间的推进,老的数据被移出、新的数据被收集到内存,如此循环。为了找到有多少会话在等待某些事件,可以使用以下脚本:
select session_id||','||session_serial# SID, n.name, wait_time, time_waited from v$active_session_history a, v$event_name n where n.event# = a.event#
这条语句的执行结果可以显示出事件的名称和花费了多少事件等待。增加ASH的字段可以帮你对某个特定的等待事件进行深入定位。例如,如果这些会话等待的事件中有一个是buffer busy wait,那就必须再做适当的诊断来定位是在哪个段上发生了等待事件。你可以通过将ASH视图中的CURRENT_OBJ#字段与DBA_OBJECTS连接查询来查到发生问题的段。
ASH还记录了并行查询服务的会话信息,这些信息对于诊断并行查询的等待事件很有用。如果记录的是并行查询的从进程的信息,协同服务会话的SID会被表示在QC_SESSION_ID字段中。字段SQL_ID记录了产生等待事件的SQL语句的ID,通过将它与视图V$SQL联合查询,可以找出这个令人讨厌的SQL语句。CLIENT_ID可以使在如web应用这样的共享用户环境中更容易定位是哪个客户端,这个字段可以通过存储过程DBMS_SESSION.SET_IDENTIFIER来设置。
既然ASH的信息如此有价值,那么不是把它的数据像AWR一样永久的存储起来不是更好吗?MMON进程会将这些信息存储到磁盘以服务于AWR表,并且可以通过视图DBA_HIST_ACTIVE_SESS_HISTORY来查询。
手工收集
在默认情况下,这些快照信息是自动收集的。但是你也可以随时手工收集。所有的AWR的功能都可以通过包DBMS_WORKLOAD_REPOSITORY来实现。要产生一个快照,只要执行:exec dbms_workload_repository.create_snapshot就可以了。
这样会立即产生一个快照记录在表WRM$_SNAPSHOT中,并且在典型(TYPICAL)级别上收集度量数据。如果需要收集更细的统计数据,可以在上述存储过程执行时设定参数FLUSH_LEVEL为ALL。统计数据的删除也是自动的,但也可以通过执行存储过程drop_snapshot_range()来手工删除。
基准线
一个典型的性能调优过程时从收集一个度量数据集的基准线开始,然后调整,再收集另一个基准线集。通过比较这两个基准数据集来观察调整产生的效果。在AWR中,可以通过已经存在的多个快照做处理来进行类似的推理。假设一个名叫apply_interest的显著产生性能压力的进程在下午1:00到3:00之间运行,相应的快照ID是从56到59,我们可以用以下存储过程为这些快照定一个名叫apply_interest_1的基准线:
exec dbms_workload_repository.create_baseline(56,59,’apply_interest_1’);
这一操作标识了从56到59的快照作为名为“apply_interest_1”的基准线的一部分。
用以下语句检查已经存在的基准线:
SQL> select * from dba_hist_baseline; DBID BASELINE_ID BASELINE_NAME START_SNAP_ID END_SNAP_ID ---------- ----------- -------------------- ------------- ----------- 4133493568 1 apply_interest_1 56 59
经过一些调优步骤,我们再创建另外一个基准线,名叫“apply_interest_2”,并比较与仅与两个基准线相关的快照的度量数据。像这样将一些快照独立成这样一些基准线能帮助了解性能调优产生的效果。分析完毕后,可以通过调用存储过程drop_baselin()来删除这些基准线,而快照还是会被保留。同样的,当清除规则需要清除掉旧的快照信息时,与这些旧快照信息相关的基准线不会被清除,以便于以后的进一步深入分析。