我见过许多开发人员都认为调试代码会带来开销,认为系统投入生产阶段之前必须把这些调试代码去掉,希望从代码中“挤出”点滴的性能。当然,随后他们可能又会发现代码中有一个“bug”,或者“运行得没有应有的那么快”(最终用户也把这称为“bug”。对于最终用户来说,性能差就是bug!)。此时,他们多么希望调试代码还在原处未被删掉(或者,如果原来没有加过调试代码,他们可能很后悔当初为什么没有添加)。特别是,他们无法再向生产系统中添加调试代码,在生产环境中,新代码必须先经过测试,这可不是说添加就添加那么轻松。
Oracle数据库(以及应用服务器和Oracle应用)都是可以充分测量的。数据库中这种测量性反映在以下几方面:
q V$视图:大多数V$视图都包含“调试”信息。V$WAITSTAT、V$SESSION_EVENT还有其他许多V$视图之所以存在,就是为了让我们知道内核内部到底发生了什么。
q 审计命令:利用这个命令,你能指定数据库要记录哪些事件以便日后分析。
q 资源管理器(DBMS_RESOURCE_MANAGER):这个特性允许你对数据库中的资源(CPU、I/O等)实现微管理。正是因为数据库能访问描述资源使用情况的所有运行时统计信息,所以才可能有资源管理器。
q Oracle“事件”:基于Oracle事件,能让Oracle生成所需的跟踪或诊断信息。
q DBMS_TRACE:这是PL/SQL引擎中的一个工具,它会全面地记录存储过程的调用树、所产生的异常,以及遇到的错误。
q 数据库事件触发器:这些触发器(如ON SERVERERROR)允许你监控和记录你觉得“意外”或非正常的情况。例如,可以记录发生“临时空间用尽”错误时正在运行的SQL。
q SQL_TRACE:这个SQL跟踪工具还可以采用一种扩展方式使用,即通过10046 Oracle事件。
还不止这些。在应用设计和开发中,测量至关重要,每一版Oracle数据库的测量性都越来越好。实际上,Oracle9i Release 2 和Oracle 10g Release 1这两个版本之间增加的测量代码量就相当显著。Oracle 10g 将内核中的代码测量发展到一个全新的层次。
在这一节中,我们将重点讨论各种跟踪文件中的信息。这里会分析有哪些跟踪文件,这些跟踪文件存放在哪里,以及对这些跟踪文件能做些什么。
通常有两类跟踪文件,对这两类跟踪文件的处理完全不同:
q 你想要的跟踪文件:例如,启用SQL_TRACE=TRUE选项的结果,其中包含有关会话的诊断信息,有助于你调整应用,优化应用的性能,并诊断出遭遇的瓶颈。
q 你不想要的跟踪文件,但是由于出现了以下错误,服务器会自动生成这些跟踪文件。这些错误包括ORA-00600“Internal Error”(内部错误)、ORA-03113“End of file on communication channel”(通信通道上文件结束)或ORA-07445“Exception Encountered”(遇到异常)。这些跟踪文件包含一些诊断信息,它们主要对Oracle Support的分析人员有用,但对我们来说,除了能看出应用中哪里出现了内部错误之外,用处不大。
3.2.1 请求的跟踪文件
你想要的跟踪文件通常都是因为设置了SQL_TRACE=TRUE生成的结果,或者是通过10046事件使用扩展的跟踪工具生成的,如下所示:

1. 文件位置
不论是使用SQL_TRACE还是扩展的跟踪工具,Oracle都会在数据库服务器主机的以下两个位置生成一个跟踪文件:
q 如果使用专用服务器连接,会在USER_DUMP_DEST参数指定的目录中生成跟踪文件。
q 如果使用共享服务器连接,则在BACKGROUND_DUMP_DEST参数指定的目录中生成跟踪文件。
要想知道跟踪文件放在哪里,可以从SQL*Plus执行SHOW PARAMETER DUMP_DEST命令来查看,也可以直接查询V$PARAMETER视图:

![]()
这里显示了3个转储(跟踪)目标。后台转储(background dump)目标由所有“服务器”进程使用(第5章会全面介绍Oracle后台进程及其作用)。
如果使用Oracle的共享服务器连接,就会使用一个后台进程;因此,跟踪文件的位置由BACKGROUND_DUMP_DEST确定。如果使用的是专用服务器连接,则会使用一个用户或前台进程与Oracle交互;所以跟踪文件会放在USER_DUMP_DEST参数指定的目录中。如果出现严重的Oracle内部错误(如UNIX上的“segmentation fault”错误),或者如果Oracle Support要求你生成一个跟踪文件来得到额外的调试信息,CORE_DUMP_DEST参数则定义了此时这个“内核”文件应该放在哪里。一般而言,我们只对后台和用户转储目标感兴趣。需要说明,除非特别指出,这本书里都使用专用服务器连接。
如果你无法访问V$PARAMETER视图,那么可以使用DBMS_UTILITY来访问大多数(但不是全部)参数的值。从下面的例子可以看出,要看到这个信息(还不止这些),只需要CREATE SESSION权限:


2. 命名约定
Oracle中跟踪文件的命名约定总在变化,不过,如果把你的系统上的跟踪文件名作为示例,应该能很容易地看出这些命名有一个模板。例如,在我的各台服务器上,跟踪文件名如表3-1所示。
表3-1 跟踪文件名示例
|
跟踪文件名 |
平 台 |
数据库版本 |
|
ora10g_ora_24574.trc |
Linux |
10g Release 1 |
|
ora9ir2_ora_24628.trc |
Linux |
9i Release 2 |
|
ora_10583.trc |
Linux |
9i Release 1 |
|
ora9ir2w_ora_688.trc |
Windows |
9i Release 2 |
|
ora10g_ora_1256.trc |
Windows |
10g Release 1 |
在我的服务器上,跟踪文件名可以分为以下几部分:
q 文件名的第一部分是ORACLE_SID(但Oracle9i Release 1例外,在这一版本中,Oracle决定去掉这一部分)。
q 文件名的下一部分只有一个ora。
q 跟踪文件名中的数字是专用服务器的进程ID, 可以从V$PROCESS视图得到。
因此,在实际中(假设使用专用服务器模式),需要访问4个视图:
q V$PARAMETER:找到USER_DUMP_DEST指定的跟踪文件位置。
q V$PROCESS:查找进程ID。
q V$SESSION:正确地标识其他视图中的会话信息。
q V$INSTANCE:得到ORACLE_SID。
前面提到过,可以使用DBMS_UTILITY来找到位置,而且通常你“知道”ORACLE_SID,所以从理论上讲只需要访问V$SESSION和V$PROCESS,但是,为了便于使用,这4个视图你可能都想访问。
以下查询可以生成跟踪文件名:

显然,在Windows平台上要把 / 换成 \。如果使用9i Release 1,只需发出以下查询,不用在跟踪文件名中增加实例名:
![]()
3. 对跟踪文件加标记
有一种办法可以对跟踪文件“加标记”,这样即使你无权访问V$PROCESS和V$SESSION,也能找到跟踪文件。假设你能读取USER_DUMP_DEST目录,就可以使用会话参数TRACEFILE_IDENTIFIER。采用这种方法,可以为跟踪文件名增加一个可以惟一标识的串,例如:

可以看到,跟踪文件还是采用标准的<ORACLE_SID>_ora_<PROCESS_ID>格式命名,但是这里还有我们为它指定的一个惟一的串,这样就能很容易地找到“我们的”跟踪文件名。
3.2.2 针对内部错误生成的跟踪文件
这一节最后我再来谈谈另一类跟踪文件,这些跟踪文件不是我们想要的,只是由于ORA-00600或另外某个内部错误而自动生成。对这些跟踪文件我们能做些什么吗?
答案很简单,一般来讲,这些跟踪文件不是给你我用的。它们只对Oracle Support有用。不过,我们向Oracle Support提交iTAR时,这些跟踪文件会很有用。有一点很重要:如果得到内部错误,修改这个错误的惟一办法就是提交一个iTAR。如果你只是将错误忽略,除非出现意外,否则它们不会自行修正。
例如,在Oracle 10g Release 1中,如果创建下表,并运行以下查询,就会得到一个内部错误(也可能不会得到错误,因为这个错误已经作为一个bug提交,并在后来的补丁版本中得到修正):


如果你是一名DBA,会发现用户转储目标中突然冒出这个跟踪文件。 或者,如果你是一名开发人员,你的应用将产生一个ORA-00600错误,你肯定想知道到底发生了什么。跟踪文件中信息很多(实际上,另外还有35 000行),但一般来讲,这些信息对你我来说都没有用。我们只是想压缩这个跟踪文件,并将其上传来完成iTAR处理。
不过,确实有些信息能帮助你跟踪到“谁”造成了错误,错误是“什么”,以及错误在“哪里”,另外,利用http://metalink.oracle.com,你还能发现这些问题是不是别人已经遇到过(许多次),以及为什么会出现这些错误。快速检查一下跟踪文件的最前面,你会得到一些有用的信息,如:


你在http://metalink.oracle.com上提交iTAR时,数据库信息当然很重要,不仅如此,如果在http://metalink.oracle.com上查看是否以前已经提出过这个问题,这些数据库信息也很有用。另外,可以看出错误出现在哪个Oracle实例上。并发地运行多个实例是很常见的,所以把问题隔离到一个实例上会很有用。

跟踪文件中的这一部分是Oracle 10g新增的,Oracle9i里没有。它显示了V$SESSION的ACTION和MODULE列中的会话信息。这里可以看到,是一个SQL*Plus会话导致了错误(开发人员应该设置ACTION和MODULE信息;有些环境已经为你做了这项工作,如Oracle Forms和HTML DB)。
另外还可以得到SERVICE NAME。这就是连接数据库所用的服务名(这里就是SYS$USERS),由此看出没有通过TNS服务来连接。如果使用user/pass@ora10g.localdomain登录,可以看到:
![]()
其中ora10g是服务名(而不是TNS连接串;这是所连接TNS监听器中注册的最终服务)。这对于跟踪哪个进程/模块受此错误影响很有用。
最后,在查看具体的错误之前,可以看到会话ID和相关的日期/时间等进一步的标识信息(所有版本都提供了这些信息):
![]()
现在可以深入到内部看看错误本身了:


这里也有一些重要的信息。首先,可以看到产生内部错误时正在执行的SQL语句,这有助于跟踪哪个(哪些)应用会受到影响。同时,由于这里能看到SQL,所以可以研究采用哪些“迂回路线”,用不同的方法编写SQL,看看能不能很快绕过问题解决bug。另外,也可以把出问题的SQL剪切并粘贴到SQL*Plus中,看看能不能为Oracle Support提供一个可再生的测试用例(当然,这些是最棒的测试用例)。
另一个重要信息是错误码(通常是600、3113或7445)以及与错误码相关的其他参数。使用这些信息,再加上一些栈跟踪信息(显示按顺序调用的一组Oracle内部子例程),可能会发现这个bug已经报告过(还能找到解决方法、补丁等)。例如,使用以下查询串:
![]()
利用MetaLink的高级搜索(全文搜索bug数据库),很快就能发现bug 3800614, “ORA-600 [12410] ON SIMPLE QUERY WITH ANALYTIC FUNCTION”。如果访问http://metalink.oracle.com,并使用这个文本进行搜索,可以找到这个bug,了解到下一版中已经修正了这个bug,并注意到已经有相应的补丁,所有这些信息我们都能得到。很多次我都发现,所遇到的错误以前已经出现过,而且事实上已经有了修正和解决的办法。
3.2.3 跟踪文件小结
现在你知道有两种一般的跟踪文件,它们分别放在什么位置,以及如何找到这些跟踪文件。希望你使用跟踪文件主要是为了调整和改善应用的性能,而不只是提交 iTAR。最后再说一句,Oracle Support确实会利用文档中没有记录的一些“事件”,如果数据库遭遇错误,可以利用这些事件得到大量的诊断信息。例如,如果得到一个ORA-01555,但你自认为不该有这个错误,此时Oracle Support就会教你设置这种诊断事件,每次遇到错误时都会创建一个跟踪文件,由此可以帮助你准确地跟踪到为什么会产生错误。





