在复杂应用环境下监控 ORACLE 数据库性能(1)(4)
假设一个系统中不仅仅有 PHP 程序,还有 C 程序与数据库进行连接,那么数据库系统一旦出了问题,如资源消耗过多,造成死锁等,仅凭
ps ax | grep oracleORCL
是看不出什么东西的,因为这个进程是 Oracle 的 shadow 进程,命令名字都被改了,从 /proc 文件系统中提供的信息中也榨不出什么有用的东西了,所以,如果发现一个进程 ( 这是 ps ax 的实际输出 ) 如下,
10406 ? R 159:10 oracleORCL (DESCRIPTION=(LOCAL=no)(ADDRESS=(PROTOCOL=
确定这个进程长时间处于 running 状态的肇事者就成为一个难题,首先,进程的运行者是 oracle, 连接者却可能是来自本机,来自局域网络,来自 internet 的 nobody 用户,所以冤无头,债无主。
查看 v$session, v$process, v$..., 也没有关于客户端的足够信息。 可以用来缩小范围的是 SQL 语句,但仍不足以构成充分的说服力让某一应用的开发人员确信是自己的程序出了问题。 观察字段丰富的 v$session 视图,里面有一个十分诱人的 client_info 字段,顾名思义,不能不让人想入非非 : 一定是关于 ORACLE 客户端的信息的,可惜它一般是 NULL 值 :-(, 笔者从 ORACLE 文档中终于发现了
dbms_application_info.set_client_info(string);
是用来设置连接 ORACLE 的客户端信息的一个包,拿来 PRO*C 中运行 :
EXEC SQL EXECUTE
BEGIN
dbms_application_info.set_client_info(' 某应用程序 : 其 PID, 文件名,行号 ');
END:
END-EXEC;
运行该 PRO*C 程序,执行一条 SQL 语句,并在关闭光标之前故意让它sleep(1000); 以腾出足够多的时间来观察 v$session 中的 client_info 字段,
[bash$] sqlplus sys/change_on_install@orcl
SQL> select distinct * from (select a.client_info,b.sql_text,c.spid
> from v$session a,v$sql b,v$process c where a.client_info is not null
> and a.sql_hash_value=b.hash_value and a.paddr=c.addr);
正是 !!! 你刚才设定的 ' 某应用程序 : 其 PID, 文件名,行号 ' 信息,别嫌短,这个 client_info 字段是 64 个字节。 够了. 看能不能让这宝贵功能施于 PHP:
$conn = OCILogon("username", "password", "dblink");
$stmt_client = OCIParse($conn, "call dbms_application_info.set_client_info('PHP:$filename:$line')");
OCIExecute($stmt_client);
OCIFreeStatement($stmt_client);
$stmt = OCIParse($conn, "select ID from users where name='slimzhao'");
OCIDefineByName($stmt, ID, $name);
OCIExecute($stmt);
OCIFetch($stmt);
sleep(1000); // 故意的
OCIFreeStatement($stmt);
OCILogoff($conn);
到 SQLPLUS 下一看,果不其然 !!! 将该功能加入前面的配置文件中,将会对 PHP 中的 SQL 语句进行更精确的跟踪定位。
至此,可以将数据库服务器下某一 oracle 的 shadow 进程与具体哪一个应用程序,甚至是哪一个源文件,哪一行的信息以及所执行的 SQL 语句等一一对应起来,有了这根主线,其它问题的分析就可步步深入,耗了多少时间,读了多少个数据块,进行了多少次排序,等等问题,都可通过视图收集到足够的信息。 本文重点不在于此,仅作抛砖,就此打住。



