国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

復(fù)雜應(yīng)用環(huán)境下監(jiān)控Oracle數(shù)據(jù)庫(kù)性能

瀏覽:5日期:2023-11-14 09:51:03
前言 : 在單一的應(yīng)用環(huán)境或業(yè)務(wù)相對(duì)簡(jiǎn)單的系統(tǒng)下,系統(tǒng)性能問(wèn)題 , 瓶頸所在往往是不言自明,解決問(wèn)題的前提 -- 定位問(wèn)題是比較輕易解決的 , 但在一個(gè)復(fù)雜的應(yīng)用環(huán)境下,各應(yīng)用系統(tǒng)對(duì)系統(tǒng)資源往往是一種共享和競(jìng)爭(zhēng)的關(guān)系,而且應(yīng)用系統(tǒng)之間也可能存在著共生或制約的關(guān)系,資源利益的均衡往往是此消彼長(zhǎng),而這種環(huán)境下的應(yīng)用系統(tǒng)一旦出現(xiàn)資源競(jìng)爭(zhēng),系統(tǒng)的瓶頸往往難以斷定,甚至?xí)l(fā)生不同應(yīng)用設(shè)計(jì)人員之間互相推諉責(zé)任的扯皮現(xiàn)象 , 本文僅就此問(wèn)題對(duì) Linux 平臺(tái)下各應(yīng)用系統(tǒng)對(duì) Oracle 數(shù)據(jù)庫(kù)的使用情況作一探討,ORACLE 數(shù)據(jù)庫(kù)的 TUNING 不是一個(gè)可以一言以蔽的主題,本文無(wú)意概全,內(nèi)容僅涉及問(wèn)題的定位及各應(yīng)用對(duì)數(shù)據(jù)庫(kù)資源的共享與競(jìng)爭(zhēng)問(wèn)題。 本文試驗(yàn)及問(wèn)題取證的環(huán)境 : RedHat6.1 Web server(Apache1.3.9+PHP4.0)+Client/Server(Pro*C) 之 Server 端 RedHat6.2 + Oracle8.1.6.1.0 RedHat7.1 Web server(Apache1.3.20+PHP4.06) + Oracle8.1.7.0.0 為方便問(wèn)題的討論 , 應(yīng)用系統(tǒng)已做簡(jiǎn)化 , 競(jìng)爭(zhēng)方僅包括一個(gè) Pro*C 的 daemon 程序作為 C/S 模式的服務(wù)端 , 和由 Apache+PHP 所支持的 WEB 網(wǎng)站業(yè)務(wù)。 1. 單個(gè) SQL 語(yǔ)句的處理 首先,最簡(jiǎn)單的情況莫過(guò)于單個(gè) SQL 語(yǔ)句的分析 , SQL 語(yǔ)句的優(yōu)化也是數(shù)據(jù)庫(kù)優(yōu)化的一個(gè)最直接最立竿見(jiàn)影的因素 . SQL 語(yǔ)句的性能監(jiān)控從監(jiān)控工具來(lái)說(shuō)大致可分為由高級(jí)語(yǔ)言提供和由 ORACLE 本身提供 , 高級(jí)語(yǔ)言以典型的應(yīng)用 C 語(yǔ)言和 WEB 開(kāi)發(fā)語(yǔ)言 PHP 為例 , C 語(yǔ)言中可以用 gettimeofday 函數(shù)來(lái)在某一數(shù)據(jù)庫(kù)操作之前和之后分別獲取一個(gè)時(shí)間值 , 將兩個(gè)時(shí)間值之差做為衡量該數(shù)據(jù)庫(kù)操作的效率 , 在 PHP 中 , 也可以用 gettimeofday, 操作方法當(dāng)然與 C 語(yǔ)言中有所不同 . 當(dāng)然 , PHP 中也有其它一些函數(shù)可以達(dá)到同樣的時(shí)間精度 , 關(guān)于時(shí)間精度的考慮 , 不能簡(jiǎn)單以大小衡量微秒級(jí)的時(shí)間數(shù)值 , 因?yàn)闀r(shí)鐘中斷的時(shí)間間隔從根本上決定了時(shí)間計(jì)算所能達(dá)到的精度 , 此外 , 操作系統(tǒng)本身對(duì)進(jìn)程的時(shí)間片分配 , 及進(jìn)程切換的開(kāi)銷(xiāo)等因素也在一定程度上影響時(shí)間數(shù)據(jù)的意義 . 所以 , 以下時(shí)間的計(jì)算最理想的情況是對(duì)同一操作在盡可能避免緩存的情況下進(jìn)行多次的循環(huán)操作 , 取總的時(shí)間值加以平均,從而得到比較接近真實(shí)情況的時(shí)間值。 C 語(yǔ)言的例子 : #define TV_START 0 #define TV_END 1 int how_long(int cmd, char *res); strUCt CMD_TIME{ int times; /* times occured within specified package number */ struct timeval time; /* total time consumed by the cmd */ }; void foo() { int id; how_long(TV_START, NULL); EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL WHENEVER NOT FOUND CONTINUE; EXEC SQL select user_id into :id from users where name='slimzhao';2; how_long(TV_END, time_consume); puts(time_consume); } int how_long(int cmd, char *res) /* return value: -1 error, 0 sucess , res: 20 bytes is enough */ { static struct timeval before, after; if(cmd == TV_START) { gettimeofday(&before, NULL); return 0; } else if(cmd == TV_END) { gettimeofday(&after, NULL); if(res) { if(after.tv_usec > before.tv_usec) { sprintf(res, '%ld %ld', after.tv_sec - before.tv_sec, after.tv_usec - before.tv_usec); } else { sprintf(res, '%ld %ld', after.tv_sec - before.tv_sec - 1, 1000000 + after.tv_usec - before.tv_usec); } } return 0; } else { return -1; } }下面是一個(gè) PHP 的例子( 為簡(jiǎn)化起見(jiàn) , 程序的錯(cuò)誤檢查被忽略) <? include '<path_to_file>/how_long.inc'; how_long(TV_START, $timestr); $conn = OCILogon('username', 'passWord', 'dblink'); $stmt = OCIParse($conn, 'select ID from users where name='slimzhao''); OCIDefineByName($stmt, ID, $id); OCIExecute($stmt); OCIFetch($stmt); OCIFreeStatement($stmt); OCILogoff($conn); how_long(TV_END, $timestr); echo ' 用戶(hù) ID: $id , 該操作消耗時(shí)間 :$timestr<br>'; ?> 其中 how_long 函數(shù)的 PHP 版本如下 : <? # 作者 : [email protected] # 當(dāng)前維護(hù)人 : [email protected] # 創(chuàng)建日期 : 2001.12.04 00:18:00 # 目的 , 在一個(gè)操作之前或之后調(diào)用該函數(shù)的不同版本 , 將得到一個(gè)記載了該操作 # 耗費(fèi)時(shí)間的字符串 , 該函數(shù)本身的開(kāi)銷(xiāo)不計(jì)入其中 . define('TV_START', 0); define('TV_END', 1); function how_long($operation, &$str) # 返回值 : 0-- 成功 , -1-- 傳遞了非法的參數(shù) . { global $before_SQL, $after_SQL; if($operation == TV_START) { $before_SQL = gettimeofday(); return 0; } else if($operation == TV_END) { $after_SQL = gettimeofday(); if($before_SQL['usec'] > $after_SQL['usec']) { $str = ($after_SQL['sec'] - $before_SQL['sec'] - 1).' 秒 '. ($after_SQL['usec'] + 1000*1000 -$before_SQL['usec']).' 微秒 '; } else { $str = ($after_SQL['sec'] - $before_SQL['sec']).' 秒 '. ($after_SQL['usec']-$before_SQL['usec']).' 微秒 '; } } else { return -1; } } ?>上面的數(shù)據(jù)庫(kù)操作開(kāi)銷(xiāo)的計(jì)算僅限于對(duì)時(shí)間消耗的計(jì)算 , 對(duì)同時(shí)使用同一數(shù)據(jù)庫(kù)的其它應(yīng)用軟件的影響 , 對(duì)磁盤(pán)操作的頻繁程度 , 數(shù)據(jù)庫(kù)操作所采取的具體策略等等因素 , 都未考慮在內(nèi) , 高級(jí)語(yǔ)言也不可能提供這樣的參考數(shù)據(jù) . 而數(shù)據(jù)庫(kù)本身提供的監(jiān)測(cè)手段彌補(bǔ)了這一不足 . 最簡(jiǎn)單的操作控制臺(tái) : sqlplus SQL> set timing on將為每次執(zhí)行的數(shù)據(jù)庫(kù)操作進(jìn)行計(jì)時(shí) , 精度為 1/100 秒 , 筆者對(duì)該功能的使用中發(fā)現(xiàn)其時(shí)間的計(jì)算也有一定的偏差 . 而且時(shí)間偏差很大 , 嚴(yán)格說(shuō)來(lái) , 已不屬于誤差的范圍 , 該歸錯(cuò)誤了 , 下面是一個(gè)例子中得到的數(shù)據(jù) : [bash$] cat tmp.sql set timing on host date; select count(*) from users; host date; SQL> @tmp.sql Wed Dec 5 00:21:01 CST 2001 COUNT(*) ---------- 1243807 Elapsed: 00:00:06.16 Wed Dec 5 00:21:05 CST 2001從系統(tǒng)的時(shí)間差來(lái)看 , 為 4 秒左右 , 但 ORACLE 卻報(bào)告了 6.16 秒 ! 假如說(shuō) ORACLE 工具在時(shí)間計(jì)算上太差強(qiáng)人意的話(huà) , 在 SQL 語(yǔ)句的執(zhí)行方案上可算是對(duì) SQL 語(yǔ)句如何執(zhí)行的最權(quán)威的詮釋了 . 解讀這樣的信息需要對(duì) ORACLE 內(nèi)部對(duì) SQL 操作的過(guò)程有一定了解 , 下面是該功能的一樣典型示例 : SQL> set autotrace on SQL> select count(*) from users; COUNT(*) ---------- 1243807 Execution Plan 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1) 1 0 SORT (AGGREGATE) 2 1 INDEX (FAST FULL SCAN) OF 'USER_BASEINFO$NAME' (UNIQUE) (Cost=4 Card=1244840) Statistics 0 recursive calls 4 db block gets 3032 consistent gets 3033 physical reads 0 redo size 370 bytes sent via SQL*Net to client 424 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processedExecution Plan 下的信息顯示 ORACLE 制定了一個(gè)什么樣的計(jì)劃來(lái)完成 SQL 操作的 ,SQL 語(yǔ)言是一種 4GL 語(yǔ)言 , 其特點(diǎn)是告訴系統(tǒng)做什么 , 而不提供如何做的信息 . 當(dāng)然 , 最終的具體工作總得有人做的 , 只是由數(shù)據(jù)庫(kù)自動(dòng)制定而不是程序員人為指定一個(gè)具體的操作步驟 , 制作這個(gè)步驟當(dāng)然要有所依據(jù) , ORACLE 有兩個(gè)基本原則來(lái)決定如何優(yōu)化 : cost-based( 基于開(kāi)銷(xiāo)的優(yōu)化 ) 和 rule-based( 基于規(guī)則的優(yōu)化 ). 基于開(kāi)銷(xiāo)的優(yōu)化的工作方式依靠于數(shù)據(jù)庫(kù)對(duì) SQL 語(yǔ)句所操作的數(shù)據(jù)對(duì)象 ( 可簡(jiǎn)單認(rèn)為就是表 ) 的數(shù)據(jù)特征的統(tǒng)計(jì)特性進(jìn)行收集和分析 . 收集分析的工作由 DBA 來(lái)定期執(zhí)行 , 時(shí)間間隔依數(shù)據(jù)變化頻率而定 , 以保持統(tǒng)計(jì)數(shù)據(jù)一定的準(zhǔn)確性 , 具體操作請(qǐng)參照 analyze 語(yǔ)句 . Oracle 預(yù)備在將來(lái)的版本中取消對(duì)基于開(kāi)銷(xiāo)的優(yōu)化方案的支持 , 因?yàn)檫@種方案需要大量的數(shù)據(jù)收集與分析工作 , 且總會(huì)有一定的誤差 , 這造成最終的執(zhí)行方案往往不是最優(yōu)的。 基于規(guī)則的優(yōu)化則是依據(jù)一些數(shù)據(jù)操作效率的規(guī)則進(jìn)行選擇 , 優(yōu)化的核心在于效率 , 時(shí)間上盡可能短 , 空間上盡可能少進(jìn)行 IO 操作 . 兩種優(yōu)化方案都絕非十全十美 , ORACLE 雖將其稱(chēng)為優(yōu)化方案 , 筆者的觀察結(jié)果表明 , ORACLE 制定出一個(gè)不是最優(yōu)或錯(cuò)誤的執(zhí)行方案也是完全可能的 . 以上為例 , Oracle 的優(yōu)化策略是 Choose, 所謂 Choose 就是 cost-based 或 rule-based , 讓 ORACLE 自己選擇 , 可以通過(guò)數(shù)據(jù)庫(kù)啟動(dòng)初始化文件 initXXX.ora 文件中的 optimizer_mode 參數(shù)來(lái)指定。 言歸正傳 , 上面的具體策略是 Oracle 對(duì)該表的一個(gè)唯一索引進(jìn)行全掃描 , 因?yàn)樵跀?shù)據(jù)庫(kù)里一個(gè)字段假如可以建立一個(gè) UNIQUE 類(lèi)型的索引 , 那么它就與表中的記錄有一一對(duì)應(yīng)的關(guān)系。所以對(duì)該索引進(jìn)行 count(*) 可以保證其值等于對(duì)表進(jìn)行 count(*) 操作。對(duì)索引進(jìn)行全掃描后的上層操作是一個(gè)集合操作 , 即對(duì)找到的每個(gè)索引記錄進(jìn)行計(jì)數(shù)。對(duì)這些信息的觀察主要用來(lái)確定 ORACLE 是否選用了 SQL 程序員希望 ORACLE 選用的索引操作。 Statistics 給出了執(zhí)行該 SQL 操作所消耗的資源的統(tǒng)計(jì)數(shù)據(jù) , 信息的表達(dá)一目了然 , 所有這些值都是越小越好 , 以通過(guò) SQL*Net 的數(shù)據(jù)吞吐量為例 , 在 OCI 編程中使用以下技術(shù)可顯著減少網(wǎng)絡(luò)流量 : 通過(guò)將 Commit 操作與 Execute 操作綁定為一個(gè)操作 . 通過(guò)對(duì)數(shù)組進(jìn)行成批數(shù)據(jù)的 delete, insert, update, 通過(guò)對(duì)一個(gè) SELECT 語(yǔ)句指定一個(gè)預(yù)取記錄數(shù) . 這些統(tǒng)計(jì)數(shù)據(jù)中 , 尤其需要避免的是涉及磁盤(pán)存取的操作 , 因?yàn)槎嗉?jí)存儲(chǔ)的操作速度是 CPU >> Memory >> HD > Disc > network > disk。2. 對(duì)投入運(yùn)營(yíng)的系統(tǒng)中 PHP 程序的監(jiān)控 理想的開(kāi)發(fā)流程是 設(shè)計(jì) -> 文檔 -> 編碼 -> 測(cè)試 -> 投入使用 , 但實(shí)際運(yùn)行的系統(tǒng)往往是由良莠不齊的程序所組成 , 有些缺乏文檔 , 有些可讀性差 , 有些程序極為脆弱。對(duì)于這樣的既成事實(shí) , 假如系統(tǒng)中出現(xiàn)了瓶頸 , 不可能一條語(yǔ)句一條語(yǔ)句地來(lái)進(jìn)行測(cè)試 , 只能是用一種統(tǒng)一的方法定位主要問(wèn)題的所在。由于 PHP 程序中的 SQL 語(yǔ)句使用了所謂動(dòng)態(tài) SQL 語(yǔ)句 , 即用 戶(hù)可以在程序運(yùn)行時(shí)動(dòng)態(tài)生成一個(gè) SQL 語(yǔ)句, 所以假如對(duì)靜態(tài)的 PHP 程序文件進(jìn)行。 ( 如用 grep 工具 ) 可能會(huì)搜捕不到成形的完整 SQL 語(yǔ)句 , 這就要求用一種動(dòng)態(tài)方法來(lái)攔截實(shí)際執(zhí)行的每一個(gè)完整的 SQL 語(yǔ)句 , 觀察 PHP 中關(guān)于 ORACLE 數(shù)據(jù)庫(kù)操作的函數(shù)簇 , 發(fā)現(xiàn) OCIParse 和 Ora_Parse 兩個(gè)函數(shù)是 SQL 語(yǔ)句的入口 , 而將這兩個(gè)函數(shù)統(tǒng)一替換為一個(gè)用戶(hù)自定義的函數(shù)即可實(shí)現(xiàn)對(duì) SQL 語(yǔ)句的攔截 , 在筆者涉入的實(shí)際系統(tǒng)中 , 是這樣解決的 : 首先分析該系統(tǒng)中所有的 PHP 程序文件 , 發(fā)現(xiàn)凡涉及 ORACLE 數(shù)據(jù)庫(kù)操作的都需要包含一個(gè)以 *.conf 結(jié)尾的配置文件 , 該配置文件是數(shù)據(jù)庫(kù)的用戶(hù)名 , 密碼和連接標(biāo)識(shí)符的定義文件 , 這些是開(kāi)發(fā)初期定下的規(guī)范 , 以便于對(duì)程序中共用的配置信息進(jìn)行統(tǒng)一的治理 , 以下是一個(gè) oracle.conf: <? $oracle_user='oracle_user'; $oracle_password='oracle_password'; $oracle_dbid = 'oracle_dbid'; ?>在涉及數(shù)據(jù)庫(kù)操作的 PHP 程序中 , 總有一行語(yǔ)句以引入該配置文件 : include('<path_to_file>/oracle.conf');設(shè)計(jì)一個(gè)函數(shù)如 debug_OCIParse 如下 , 以替換 OCIParse, 并將該文件放入一個(gè)叫 debug.conf 的別一個(gè)配置文件中 , 如下 : oracle.conf: <? global $impossible_conflit_with_this_oracle,$user,$password,$dbname; if(!$impossible_conflit_with_this_oracle) require('/home/httpd/debug.conf'); $impossible_conflit_with_this_oracle=1; $user='username'; $password='password'; $dbname='dblink'; ?> ========================================================== debug.conf: ========================================================== <? function debug_OCIParse($debug_conn, $debug_sql, $filename, $line) { debug_WriteLog($debug_sql, $filename, $line); return OCIParse($debug_conn, $debug_sql); } function debug_Ora_Parse($debug_conn, $debug_sql, $filename, $line) { debug_WriteLog($debug_sql, $filename, $line); return Ora_Parse($debug_conn, $debug_sql); } function debug_WriteLog($debug_sql, $filename, $line) { #if(!strstr($filename,'message.pHtml')) return; $string = date('Y-m-d H:i:s').' $filename:$linent$debug_sqln'; $fp = fopen('/home/httpd/sql.log', 'a'); fwrite($fp, $string, strlen($string)); fclose($fp); } ?>然后 , 統(tǒng)一將所有 PHP 程序中的 OCIParse 函數(shù)替換為 debug_OCIParse 函數(shù) , 并要求 PHP 程序員以后使用 debug_OCIParse 函數(shù)進(jìn)行開(kāi)發(fā) , 如下將: $stmt = OCIParse($conn, $sql);替換為 : $stmt = debug_OCIParse($conn, $sql, __FILE__, __LINE__);這個(gè)工作可由系統(tǒng)治理員統(tǒng)一做一次,以后就要要求 PHP 程序員形成規(guī)范。例 , 可用如下腳本: find /home/httpd/html -name '*.ph*' xargs -n1 while read i do ex -c ':se icg/ociparse/s/ociparse/debug_&/s/);$/,__FILE__,__LINE__&/' -c ':x!' $i done這幾行腳本并非放之皆準(zhǔn) , 但對(duì)于規(guī)范的 php 文件 , 一般來(lái)說(shuō)沒(méi)有問(wèn)題 , 筆者的系統(tǒng)中用該方法維護(hù)幾百 M 的 PHP 程序 , 少有例外 , 由于這是只運(yùn)行一次的腳本 , 所以只要根據(jù)自己具體的系統(tǒng)做適當(dāng)?shù)恼{(diào)整即可 , 如上 , 假如對(duì)含有 OCIParse 的程序行的內(nèi)容不太確定 , 可以用如下方法先進(jìn)行查看 : find /home/httpd/html -name '*.ph*' xargs grep -in ociparse > ~/list這段腳本中的 ex 命令稍作解釋: ex 是 vi 編輯器的后端工具 , 可以在命令行上使用一些編輯命令 , 每個(gè)編輯命令以 -c 選項(xiàng)開(kāi)頭 , 如上:se ic 是改變編輯器對(duì)大小寫(xiě)不敏感 , 全稱(chēng)是 :set ignorecase。 號(hào)用來(lái)間隔多個(gè)編輯命令。 g/ociparse/s/ociparse/debug_&/ 的編輯語(yǔ)意為 : 找到含有 ociparse 的行 , 對(duì)這些行執(zhí)行如下編輯命令。 s/ociparse/debug_&/, s 意為 substitute, 將 ociparse 替換為 debug_&, 這其中 & 代表前面找到的匹配字符串 , 由于是忽略大小寫(xiě)的 , 所以用 & 來(lái)保留前面找到的不管是大小寫(xiě)如何混合的字符串的原型 . 這樣 , ociparse 就會(huì)被替換為 debug_ociparse, 而 OCIParse 將會(huì)被替換為debug_OCIParse。 接下來(lái)的 s/);$/,__FILE__,__LINE__&/ 是將 ociparse 語(yǔ)句的右括號(hào)進(jìn)行替換,將用于調(diào)試監(jiān)控的兩個(gè)參數(shù)(PHP 中的宏 ) 加上,$ 不是指一個(gè)真正的字符,而是指一個(gè)特定的位置 -- 行尾,以避免無(wú)辜的 ); 被替換掉。另一個(gè)命令 -c ':x!' 是將該文件存盤(pán)退出。 打出這么一套組合拳需要你對(duì)這些命令了如指掌 , 假如你對(duì)某個(gè)文件沒(méi)有寫(xiě)權(quán) , 或出了其它岔子 , 那簡(jiǎn)直是一場(chǎng)災(zāi)難 , 這種魔法級(jí)的指令總是高風(fēng)險(xiǎn)的 , 搞不好會(huì)走火入魔 , 讓你發(fā)下毒誓有生之年不再碰它 . 所以謹(jǐn)慎與備份總是對(duì)的。3. 對(duì)各種應(yīng)用程序中的情況進(jìn)行監(jiān)控 假設(shè)一個(gè)系統(tǒng)中不僅僅有 PHP 程序,還有 C 程序與數(shù)據(jù)庫(kù)進(jìn)行連接,那么數(shù)據(jù)庫(kù)系統(tǒng)一旦出了問(wèn)題 , 如資源消耗過(guò)多,造成死鎖等,僅憑 ps ax grep oracleORCL是看不出什么東西的 , 因?yàn)檫@個(gè)進(jìn)程是 Oracle 的 shadow 進(jìn)程,命令名字都被改了,從 /proc 文件系統(tǒng)中提供的信息中也榨不出什么有用的東西了,所以,假如發(fā)現(xiàn)一個(gè)進(jìn)程 ( 這是 ps ax 的實(shí)際輸出 ) 如下: 10406 ? R 159:10 oracleORCL (DESCRIPTION=(LOCAL=no)(ADDRESS=(PROTOCOL=確定這個(gè)進(jìn)程長(zhǎng)時(shí)間處于 running 狀態(tài)的肇事者就成為一個(gè)難題 , 首先 , 進(jìn)程的運(yùn)行者是 oracle, 連接者卻可能是來(lái)自本機(jī) , 來(lái)自局域網(wǎng)絡(luò) , 來(lái)自 internet 的 nobody 用戶(hù) , 所以冤無(wú)頭,債無(wú)主。查看 v$session, v$process, v$..., 也沒(méi)有關(guān)于客戶(hù)端的足夠信息 . 可以用來(lái)縮小范圍的是 SQL 語(yǔ)句 , 但仍不足以構(gòu)成充分的說(shuō)服力讓某一應(yīng)用的開(kāi)發(fā)人員確信是自己的程序出了問(wèn)題 . 觀察字段豐富的 v$session 視圖 , 里面有一個(gè)十分誘人的 client_info 字段 , 顧名思義 , 不能不讓人想入非非 : 一定是關(guān)于 ORACLE 客戶(hù)端的信息的 , 可惜它一般是 NULL 值 :-(, 筆者從 ORACLE 文檔中終于發(fā)現(xiàn)了 dbms_application_info.set_client_info(string);是用來(lái)設(shè)置連接 ORACLE 的客戶(hù)端信息的一個(gè)包 , 拿來(lái) PRO*C 中運(yùn)行: EXEC SQL EXECUTE BEGIN dbms_application_info.set_client_info(' 某應(yīng)用程序 : 其 PID, 文件名 , 行號(hào) '); END: END-EXEC;運(yùn)行該 PRO*C 程序 , 執(zhí)行一條 SQL 語(yǔ)句 , 并在關(guān)閉光標(biāo)之前故意讓它: sleep(1000);以騰出足夠多的時(shí)間來(lái)觀察 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);正是你剛才設(shè)定的'某應(yīng)用程序:其PID,文件名,行號(hào)'信息 , 別嫌短,這個(gè) client_info 字段是 64 個(gè)字節(jié)夠了。看能不能讓這寶貴功能施于 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 下一看 , 果不其然 !!! 將該功能加入前面的配置文件中 , 將會(huì)對(duì) PHP 中的 SQL 語(yǔ)句進(jìn)行更精確的跟蹤定位。 至此,可以將數(shù)據(jù)庫(kù)服務(wù)器下某一 oracle 的 shadow 進(jìn)程與具體哪一個(gè)應(yīng)用程序,甚至是哪一個(gè)源文件,哪一行的信息以及所執(zhí)行的 SQL 語(yǔ)句等一一對(duì)應(yīng)起來(lái),有了這根主線,其它問(wèn)題的分析就可步步深入,耗了多少時(shí)間,讀了多少個(gè)數(shù)據(jù)塊 , 進(jìn)行了多少次排序,等等問(wèn)題,都可通過(guò) v$... 視圖收集到足夠的信息。本文重點(diǎn)不在于此,僅作拋磚,就此打住。
主站蜘蛛池模板: 精品9e精品视频在线观看 | 成人欧美精品大91在线 | 久久精品免费一区二区三区 | 国产美女一级视频 | 欧美高清在线精品一区 | 久久精品国产99久久香蕉 | 九九九精品视频免费 | 久久不色| 97在线公开视频 | 日本伊人精品一区二区三区 | 欧美激情中文字幕 | 频黄| 精品在线一区 | 一级特级欧美aaaaa毛片 | 精品综合在线 | 亚洲成人在线视频 | 成人精品网 | 亚洲日韩中文字幕在线播放 | 日韩一区二区三区在线 | 99re热视频这里只精品 | 日本久草网| 国产激情久久久久久影院 | 欧美一级日本一级韩国一级 | 欧美成人激情在线 | 国产精品免费一级在线观看 | 91热视频在线观看 | 久久亚洲国产伦理 | 亚洲一区二区三区久久 | 九九精品视频在线观看九九 | 国内精品a | 小屁孩cao大人免费网站 | 日韩在线观看不卡 | 欧美人成人亚洲专区中文字幕 | 日韩一级一欧美一级国产 | 成人三级在线 | 俄罗斯a级毛片 | 国产精品免费观看视频播放 | 日韩欧一级毛片在线播无遮挡 | 国产步兵社区视频在线观看 | 自拍 欧美 在线 综合 另类 | 久久99热精品免费观看欧美 |