前言:
在單一的應用環境或業務相對簡單的系統下
系統性能問題
瓶頸所在往往是不言自明
解決問題的前提
定位問題是比較容易解決的
但在一個復雜的應用環境下
各應用系統對系統資源往往是一種共享和競爭的關系
而且應用系統之間也可能存在著共生或制約的關系
資源利益的均衡往往是此消彼長
而這種環境下的應用系統一旦出現資源競爭
系統的瓶頸往往難以斷定
甚至會發生不同應用設計人員之間互相推诿責任的扯皮現象
本文僅就此問題對Linux平台下各應用系統對ORACLE數據庫的使用情況作一探討
ORACLE數據庫的TUNING不是一個可以一言以蔽的主題
本文無意概全
內容僅涉及問題的定位及各應用對數據庫資源的共享與競爭問題
本文試驗及問題取證的環境:
RedHat
Web server(Apache
+PHP
)+Client/Server(Pro*C)之Server端
RedHat
+ Oracle
RedHat
Web server(Apache
+PHP
) + Oracle
為方便問題的討論
應用系統已做簡化
競爭方僅包括一個Pro*C的daemon程序作為C/S模式的服務端
和由Apache+PHP所支持的WEB網站業務
單個SQL語句的處理
首先
最簡單的情況莫過於單個SQL語句的分析
SQL語句的優化也是數據庫優化的一個最直接最立竿見影的因素
SQL語句的性能監控從監控工具來說大致可分為由高級語言提供和由ORACLE本身提供
高級語言以典型的應用C 語言和WEB開發語言PHP為例
C語言中可以用gettimeofday函數來在某一數據庫操作之前和之後分別獲取一個時間值
將兩個時間值之差做為衡量該數據庫操作的效率
在PHP中
也可以用gettimeofday
操作方法當然與C語言中有所不同
當然
PHP中也有其它一些函數可以達到同樣的時間精度
關於時間精度的考慮
不能簡單以大小衡量微秒級的時間數值
因為時鐘中斷的時間間隔從根本上決定了時間計算所能達到的精度
此外
操作系統本身對進程的時間片分配
及進程切換的開銷等因素也在一定程度上影響時間數據的意義
所以
以下時間的計算最理想的情況是對同一操作在盡可能避免緩存的情況下進行多次的循環操作
取總的時間值加以平均
從而得到比較接近真實情況的時間值
C語言的例子:
==========================================================
#define TV_START
#define TV_END
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
;
;
how_long(TV_END
time_consume);
puts(time_consume);
}
int how_long(int cmd
char *res)
/* return value:
error
sucess
res:
bytes is enough */
{
static struct timeval before
after;
if(cmd == TV_START) {
gettimeofday(&before
NULL);
return
;
} 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
+ after
tv_usec
before
tv_usec);
}
}
return
;
} else {
return
;
}
}
==========================================================
下面是一個PHP的例子(為簡化起見
程序的錯誤檢查被忽略)
==========================================================
include
/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
用戶ID: $id
該操作消耗時間:$timestr
;
?>
其中how_long函數的PHP版本如下:
#作者:
#當前維護人:
#創建日期:
:
:
#目的
在一個操作之前或之後調用該函數的不同版本
將得到一個記載了該操作
#耗費時間的字符串
該函數本身的開銷不計入其中
define(
TV_START
);
define(
TV_END
);
function how_long($operation
&$str)
#返回值:
成功
傳遞了非法的參數
{
global $before_SQL
$after_SQL;
if($operation == TV_START) {
$before_SQL = gettimeofday();
return
;
} else if($operation == TV_END) {
$after_SQL = gettimeofday();
if($before_SQL[
usec
] > $after_SQL[
usec
]) {
$str = ($after_SQL[
sec
]
$before_SQL[
sec
]
)
秒
($after_SQL[
usec
] +
*
$before_SQL[
usec
])
微秒
;
} else {
$str = ($after_SQL[
sec
]
$before_SQL[
sec
])
秒
($after_SQL[
usec
]
$before_SQL[
usec
])
微秒
;
}
} else {
return
;
}
}
?>
============================== 上面的數據庫操作開銷的計算僅限於對時間消耗的計算
對同時使用同一數據庫的其它應用軟件的影響
對磁盤操作的頻繁程度
數據庫操作所采取的具體策略等等因素
都未考慮在內
高級語言也不可能提供這樣的參考數據
而數據庫本身提供的監測手段彌補了這一不足
最簡單的操作控制台:sqlplus
SQL> set timing on
將為每次執行的數據庫操作進行計時
精度為
/
秒
筆者對該功能的使用中發現其時間的計算也有一定的偏差
而且時間偏差很大
嚴格說來
已不屬於誤差的范圍
該歸錯誤了
下面是一個例子中得到的數據:
[bash$] cat tmp
sql
set timing on
host date;
select count(*) from users;
host date;
SQL> @tmp
sql
Wed Dec
:
:
CST
COUNT(*)
Elapsed:
:
:
Wed Dec
:
:
CST
從系統的時間差來看
為
秒左右
但ORACLE卻報告了
秒!
如果說ORACLE工具在時間計算上太差強人意的話
在SQL語句的執行方案上可算是對SQL語句如何執行的最權威的诠釋了
解讀這樣的信息需要對ORACLE內部對SQL 操作的過程有一定了解
下面是該功能的一樣典型示例:
SQL> set autotrace on
SQL> select count(*) from users;
COUNT(*)
Execution Plan
SELECT STATEMENT Optimizer=CHOOSE (Cost=
Card=
)
SORT (AGGREGATE)
INDEX (FAST FULL SCAN) OF
USER_BASEINFO$NAME
(UNIQUE)
(Cost=
Card=
)
Statistics
recursive calls
db block gets
consistent gets
physical reads
redo size
bytes sent via SQL*Net to client
bytes received via SQL*Net from client
From:http://tw.wingwit.com/Article/program/Oracle/201311/18148.html