分类: Oracle
2008-07-30 15:19:52
10g 等待界面为还没有被 ADDM 捕获的即时性能问题提供了有价值的诊断数据
“数据库太慢了!”
这句话通常出自一位严格的用户之口。如果您和我一样,那么在您的 DBA 生涯中您肯定无数次听到过这句话。
那么,您又怎样解决该问题呢?除了对用户置之不理之外(这是我们大多数人都不敢奢望的想法),您可能要做的第一件事就是查看是否有任何会话在等待数据库内部或外部的任何事件。 Oracle 提供了一个简单但一流的机制来达到此目的:V$SESSION_WAIT 视图。该视图显示了有助于您的诊断的各种信息,如一个会话正在等待或已经等待的事件,以及等待了多长时间和多少次。例如,如果会话在等待事件 "db file sequential read",列 P1 和 P2 将显示会话正在等待的块的 file_id 和 block_id。 对于大多数等待事件而言,这个视图足够了,但它还不是一个强健的调整工具,之所以如此说,至少是因为以下两个重要原因:SID : 269 SEQ# : 56 EVENT :enq:TX - row lock contention P1TEXT :name|mode P1 : 1415053318 P1RAW : 54580006 P2TEXT :usn<<16 | slot P2 : 327681 P2RAW : 00050001 P3TEXT :sequence P3 : 43 P3RAW :0000002B WAIT_CLASS_ID : 4217450380 WAIT_CLASS# : 1 WAIT_CLASS : Application WAIT_TIME : -2 SECONDS_IN_WAIT : 0 STATE :WAITED UNKNOWN TIME注意以黑体显示的列;在这些列中,WAIT_CLASS_ID、WAIT_CLASS# 和 WAIT_CLASS 是 10g 中新增的列。列 WAIT_CLASS 指示等待的类型,必须将其作为有效的等待事件解决或者作为空闲的等待事件退出。在上面的例子中,等待类显示为 Application,这表示它是一个需要您注意的等待。 该列突出显示那些能够证明与您的调整最相关的少数几条记录。例如,您可以使用如下查询来获取事件的等待会话。
select wait_class, event, sid, state, wait_time, seconds_in_wait from v$session_wait order by wait_class, event, sid /下面是一个样例输出:
WAIT_CLASS EVENT SID STATE WAIT_TIME SECONDS_IN_WAIT ---------- -------------------- ---------- ------------------- ---------- --------------- Application enq:TX - 269 WAITING 0 73 row lock contention Idle Queue Monitor Wait 270 WAITING 0 40 Idle SQL*Net message from client 265 WAITING 0 73 Idle jobq slave wait 259 WAITING 0 8485 Idle pmon timer 280 WAITING 0 73 Idle rdbms ipc message 267 WAITING 0 184770 Idle wakeup time manager 268 WAITING 0 40 Network SQL*Net message to client 272 WAITED SHORT TIME -1 0在这,您可以看到几个事件(如 Queue Monitor Wait 和 JobQueue Slave)被明确地归为 Idle 事件。您可以将它们作为非阻塞等待消除掉;不过,有时这些“空闲”事件可能指示一个内在的问题。例如,与 SQL*Net 相关的事件可能指示高网络延迟(除其他因素外)。 另一件要注意的重要的事情是,WAIT_TIME 的值为 -2。某些平台(如 Windows)不支持快速计时机制。如果在这些平台上没有设定初始化参数 TIMED_STATISTICS,那么将无法获得准确的计时统计数据。在这种情况下,在 Oracle9i 中,该列将显示一个非常大的数字,这使问题变得更加不清晰。在 10g 中,值 -2 指示这种情况 — 平台不支持快速定时机制并且没有设定 TIMED_STATISTICS。(对于本文剩下的部分,我们将假定存在一个快速计时机制。) 会话也显示等待 记得长期以来一直需要将 V$SESSION_WAIT 与 V$SESSION 结合使用以获得有关会话的其他详细信息吗?嗯,这已经成为历史了。在 10g 中,V$SESSION 视图还显示由 V$SESSION_WAIT 显示的等待。下面是 V$SESSION 视图其余的列,这些列显示了会话当前等待的等待事件。
EVENT# NUMBER EVENT VARCHAR2(64) P1TEXT VARCHAR2(64) P1 NUMBER P1RAW RAW(4) P2TEXT VARCHAR2(64) P2 NUMBER P2RAW RAW(4) P3TEXT VARCHAR2(64) P3 NUMBER P3RAW RAW(4) WAIT_CLASS_ID NUMBER WAIT_CLASS# NUMBER WAIT_CLASS VARCHAR2(64) WAIT_TIME NUMBER SECONDS_IN_WAIT NUMBER STATE VARCHAR2(19)这些列与 V$SESSION_WAIT 中的那些列相同,且显示相同的信息,从而不再需要在那个视图中查看它们了。因此,对于等待任意事件的任意会话,您仅需要查看一个视图。 让我们回到原来的问题:SID 为 269 的会话正等待事件 enq:TX — row lock contention,指示它正等待被另一个会话占用的锁。要诊断该问题,您必须识别占用锁的那个会话。但您如何才能做到这一点? 在 Oracle9i 及更低版本中,您可能得编写复杂(和极耗资源)的查询来获得占用锁的会话的 SID。而在 10g 中,您所要做的就是执行以下查询:
select BLOCKING_SESSION_STATUS, BLOCKING_SESSION from v$session where sid = 269 BLOCKING_SE BLOCKING_SESSION ----------- ---------------- VALID 265找到了:SID 为 265 的会话阻塞了会话 269。还能更容易吗? 有多少等待? 用户仍然在缠着您,因为用户的问题仍然没有得到满意的解答。为什么用户的会话花了这么长时间才完成?您可以执行以下命令来找出原因:
select * from v$session_wait_class where sid = 269;输出返回为:
SID SERIAL# WAIT_CLASS_ID WAIT_CLASS# WAIT_CLASS TOTAL_WAITS TIME_WAITED ---- ------- ------------- ----------- ------------- ----------- ----------- 269 1106 4217450380 1 Application 873 261537 269 1106 3290255840 2 Configuration 4 4 269 1106 3386400367 5 Commit 1 0 269 1106 2723168908 6 Idle 15 148408 269 1106 2000153315 7 Network 15 0 269 1106 1740759767 8 User I/O 26 1注意这里有关会话等待的大量信息。现在您知道了,该会话已经为与应用程序相关的等待等待了 873 次(共 261,537 厘秒),在与网络相关的事件中等待了 15 次等等。 以此类推,您可以使用以下查询来查看系统范围的等待类的统计数据。同样,时间是以厘秒为单位的。
select * from v$system_wait_class; WAIT_CLASS_ID WAIT_CLASS# WAIT_CLASS TOTAL_WAITS TIME_WAITED ------------- ----------- ------------- ----------- ----------- 1893977003 0 Other 2483 18108 4217450380 1 Application 1352 386101 3290255840 2 Configuration 82 230 3875070507 4 Concurrency 80 395 3386400367 5 Commit 2625 1925 2723168908 6 Idle 645527 219397953 2000153315 7 Network 2125 2 1740759767 8 User I/O 5085 3006 4108307767 9 System I/O 127979 18623大多数问题不是孤立出现的;它们留下了揭示真相的线索,模式可以识别这些线索。可以按如下方式从等待类的一个历史视图中查看模式。
select * from v$waitclassmetric;这个视图存储了最后一分钟内与等待类相关的统计数据。
select wait_class#, wait_class_id, average_waiter_count "awc", dbtime_in_wait, time_waited, wait_count from v$waitclassmetric / WAIT_CLASS# WAIT_CLASS_ID AWC DBTIME_IN_WAIT TIME_WAITED WAIT_COUNT ----------- ------------- ---- -------------- ----------- ---------- 0 1893977003 0 0 0 1 1 4217450380 2 90 1499 5 2 3290255840 0 0 4 3 3 4166625743 0 0 0 0 4 3875070507 0 0 0 1 5 3386400367 0 0 0 0 6 2723168908 59 0 351541 264 7 2000153315 0 0 0 25 8 1740759767 0 0 0 0 9 4108307767 0 0 8 100 10 2396326234 0 0 0 0 11 3871361733 0 0 0 0注意 WAIT_CLASS_ID 和相关的统计数据。对于值 4217450380,我们看到 2 个会话在最后一分钟内总共等待了该类 5 次(1,499 厘秒)。但该等待类是什么?您可以从 V$SYSTEM_WAIT_CLASS 中获取这一信息(如上所示)— 就是 Application 类。 注意名称为 DBTIME_IN_WAIT 的列,这是一个非常有用的列。在我们关于自动工作负载信息库 (AWR) 的部分中,您可能还记得在 10g 中是以更细粒化的方式来报告时间的,并且可以确定在数据库中花费的准确时间。DBTIME_IN_WAIT 显示在数据库中花费的时间。 一切都留有线索 用户终于离开了,您长舒了一口气。但您可能仍然想寻根究底,希望查明主要是哪些等待造成用户会话中的问题。当然,您可以通过查询 V$SESSION_WAIT 而轻易地得到答案 — 但不幸的是,等待事件现在不存在了,因此该视图没有它们的任何记录。您该怎么办? 在 10g 中,自动保留活动会话最后 10 个事件的会话等待历史。这个历史可通过 V$SESSION_WAIT_HISTORY 视图查看。要找出这些事件,您可以简单地执行:
select event, wait_time, wait_count from v$session_wait_history where sid = 265 / EVENT WAIT_TIME WAIT_COUNT ------------------------------ ---------- ---------- log file switch completion 2 1 log file switch completion 1 1 log file switch completion 0 1 SQL*Net message from client 49852 1 SQL*Net message to client 0 1 enq:TX - row lock contention 28 1 SQL*Net message from client 131 1 SQL*Net message to client 0 1 log file sync 2 1 log buffer space 1 1当会话变为非活动状态或断开时,记录从该视图中消失。不过,这些等待的历史保留在 AWR 表中,以便进一步分析。从 AWR 中显示会话等待的视图是 V$ACTIVE_SESSION_HISTORY。(同样,有关 AWR 的更多信息,请参考本系列的。) 结论 通过 Oracle 数据库 10g 中的等待模型的增强,分析性能问题变得非常容易。提供的会话等待历史可以帮助您在会话经历等待后诊断问题。将等待归为各种等待类还有助于您了解每种类型等待所造成的影响,这在研究正确的纠正方法时将带来便利。 有关等待事件动态性能视图和等待事件本身的更多信息,请参考《Oracle 数据库性能调整指南 10g 第 1 版 (10.1)》的。