在php中使用綁定變量的方法(Oracle SQL共享的機制)

在網站應用的開發中,一個較流行的方法便是使用 php 編程,php編程方法簡單明瞭,直接在html 中嵌入php 代碼,對於開發基於數據庫的動態應用十分方便。但是,許多開發員在用php開發基於Oracle 數據庫的應用時,仍沿習開發基於 Mysql 的應用的方法,未使用綁定變量,使得Oracle SGA 區中SQL語句的重用性極低,浪費了內存,降低了系統性能。
因而,在此,先簡單介紹一下Oracle SQL共享的機制,再介紹如何在 php 中使用綁定變量,從而實現Oracle 數據庫中 sql語句的共享。

一、Oracle SQL語句共享區的機制
1、SGA 區結構:
Oracle 數據庫啓動時,在內存中分配了一大片空間,爲系統全局區(System Global Area),其中包含 Sql 共享池及數據緩存器(Data Buffer Cache)。SGA 區的共享池部分主要由三個區域組成: 庫緩存, 字典緩存, 控制結構。庫緩存包括共享 SQL 區,私有SQL區,PL/SQL 過程及包, 及控制結構,如鎖及庫緩存handles。用戶執行過的 Sql 語句存放於 Sql 共享池中,以便可以重用,提高其效率。

2、SQL語句在內存中的分佈:
Oracle 將其執行的每一條 SQL 語句存於共享SQL 區及私有 SQL 區中。當Oracle 發現兩個用戶執行相同的SQL語句時,則爲這些用戶重用SQL共享區。但是,每一用戶必須在私有SQL區中擁有該語句的一份獨立拷貝。共享SQL 區包含單一SQL語句或相同的SQL語句的解析樹及執行計劃。通過爲多個相同的DML語句使用一個共享SQL區,Oracle 節省了內存的使用, 特別是當許多用戶使用同一應用時。 共享SQL區永遠駐留在共享池中。

3、SQL語句解析時進行的內存分配操作:
當一個SQL語句被提交至Oracle 去執行時,Oracle 自動地執行以下內存分配步驟:
Oracle 檢查共享池,看是否在共享SQL區中已存在相同的語句。 若有,則該共享SQL區被用於執行該語句的新實例的後續操作。 相應地,若在共享池中無該語句,則Oracle在共享池中分配一新的共享SQL區,其尺寸決定於該語句的複雜性。 若一個SQL語句要求新的共享SQL區而整個共享池已被分配完畢,則 Oracle 可通過一個最近最少修改機理從共享池中釋放部分項目,直至可爲新語句的共享SQL區提供足夠的空間。 若 Oracle釋放了一個共享 SQL 區,則與該區相關聯的SQL語句在下次重執行時,須重新解析並重新分配至另一共享SQL區。 在兩種情況下,用戶專用SQL區與包含該語句的共享SQL區相關聯。
因而,若能使語句得到共享,則其將減少內存的佔用,同時,減少了cpu 的佔用,加快了語句執行的速度。
即使一個光標仍處於打開狀態,若其很久未被使用了,則其共享區也可能被從共享池中移出。若該光標以後又被用於執行其語句,則Oracle重解析該語句並且在共享池中分配一新的共享SQL區。

4、私有SQL區
私有SQL區包含綁定信息及運行時緩衝等數據。 每一個提交一個SQL語句的會話均有一個私有SQL區。 每一提交相同SQL語句的用戶有其使用單一共享SQL區的私有SQL區。許多私有SQL區可以與同一共享SQL區相關聯
一個私有SQL區包括一個永久區和一個運行時區:
一個永久區包含在執行過程中保持的綁定信息,數據類型轉換的代碼(在定義的數據類型與查詢列的數據類型不一致時), 及其它狀態信息(比如遞歸或遠程光標數或並行查詢的狀態)。 永久區的尺寸決定於綁定變量的數目及語句中指定的列數。 例如, 若一個查詢中指定了很多列,則永久區要大一些。
運行時區包含SQL語句被執行時使用的一些信息。 運行時區的尺寸信賴於被執行的SQL語句的類型及其複雜性及被該語句處理的行的尺寸。 一般而言, 用於INSERT, UPDATE, 及 DELETE 的語句其運行區要比 SELECT 語句所需的運行區尺寸要小。

二、在 php 中不使用綁定變量與使用綁定變量的語法對比
在 php 中,若不使用綁定變量,其對數據庫的操作語法爲:

先解析已用變量值取代變量的語句,
ora_parse(光標號,"包含變量的值的sql語句");
再執行語句
ora_exec(光標號);

使用綁定變量後,語法爲先解析不含變量值的使用綁定變量的語句,再將php 變量與sql 中綁定變量相綁定,然後爲爲變量賦值,最後爲執行語句。
如此,則儘管變量值可不斷改變,但語句不會變化,從而可避免不必要的解析。
ora_parse(光標號,"包含未與變量對應的綁定變量的sql語句");
ora_bind(int 光標號, string PHP 變量名, string SQL 參數名, int 變量值長, int [變量類型] );
語法中的 type 爲可省略的參數選項,可以設成下面三種數字之一:0 爲內定值,表示輸入/輸出 (in/out);1 表示輸入 (in);2 表示輸出 (out)。
然後,爲爲php變量進行賦值。
最後,才爲執行該語句。
ora_exec(光標號);

三、在 php 中不使用綁定變量與使用綁定變量的對比示例
1、示例1,在select 語句中使用綁定變量:
語句:select sid, serial#, machine from v$session where username='用戶名';
假設執行三次,其參數值分別爲 user1, user2, user3

未使用綁定變量時,其語句爲:
ora_parse($list_cursor, "select sid, serial#, machine from v$session where username=$var_username");
ora_execute($list_cursor);

內存中SQL共享區中便會存在以下三條語句:
select sid, serial#, machine from v$session where username='user1';
select sid, serial#, machine from v$session where username='user2';
select sid, serial#, machine from v$session where username='user3';
由於每次執行時,語句中的var_username 值不同,從而語句便相應地不同,使得其無法共享。


使用綁定變量時,其語法爲:
先解析僅含綁定變量 p_1(p: parameter,參數),但無變量值的語句
ora_parse($list_cursor, "select sid, serial#, machine from v$session where username=:p1");
再將 php 程序變量 v_1 (v: Variable 變量)與 sql 語句中的綁定變量 p_1 相綁定,
ora_bind($list_cursor,"v_1","p_1",strlen($var_username),1);
在執行語句前,對該php 程序變量進行賦值
$v_1= $var_username;
然後,執行語句。
ora_exec($list_cursor);

內存中SQL共享區中只會存在以下一條語句:
select sid, serial#, machine from v$session where username=:p_1;
而參數值user1, user2, user3 則存放在執行該語句的用戶會話的私有sql區

此時,在系統 sql 共享區中,將該語句分兩部分存儲,一部分爲前面僅含綁定變量的語句,爲共享部分,一部分爲含有變量值的部分,爲私有部分。由於共享部分不含值,因而,對於不同用戶不同參數值的查詢,其語句爲一致的,從而實現了共享,避免了不必要的解析。

2、示例2,在insert 語句中使用綁定變量:
語句:insert into test_table values(col1, col2);
假設執行三次,其參數值分別爲 1,2; 2,3; 3,4
未使用綁定變量時,其語法爲:
ora_parse($list_cursor, "insert into test_table values($var_col1,$var_col2)");
ora_execute($list_cursor);
內存中SQL共享區中便會存在以下三條語句:
insert into test_table values(1,2);
insert into test_table values(2,3);
insert into test_table values(3,4);

使用綁定變量後,其語句爲:
首先在原放變量的地方放入綁定變量,使其語句可以共享, 解析語句
ora_parse($list_cursor,"insert into test_table values(:p_col1,:p_col2)") or die;
將 php變量與 sql 語句中的綁定變量相綁定
ora_bind($list_cursor,"v_col0","p_col1",strlen($var_col1),1);
ora_bind($list_cursor,"v_col1","p_col2",strlen($var_col2),1);
爲php 變量進行賦值
$v_col0 = $var_col1;
$v_col1 = $var_col2;
執行語句
ora_exec($list_cursor);

內存中SQL共享區中只會存在以下一條語句:
insert into test_table values(:p_col1,:p_col2);
而參數值則存放在執行該語句的用戶會話的私有sql區, 從而由於共享部分爲一致的,可以在多用戶中實現共享。節約內存及cpu 時間。

若爲通過數組進行多組值的插入,則可將 ora_parse 及ora_bind 置於循環開始之前,因爲語句在循環中不會關閉,而且只是變量值變化,語句本身不變化,因而,只需一次解析及綁定。而將 賦值語句及 ora_exec 語句置於循環中,由於減少了函數調用及網絡傳輸的花費,更會大大提高速度。

四、在其它系統中使用綁定變量的方法:
在 PowerBuilder 開發中,對於支持綁定變量的數據庫系統,PowerBuilder 的綁定開關缺省參數爲打開,從而其在系統中參數位置爲"?",實現了語句的共享。若在連接數據庫時,將DBParm 參數的DisableBind設爲1,則關閉綁定開關,不同參數值的同一語句無法共享。
在 Oracle Developer2000 開發的應用中,系統也爲默認使用綁定變量。但是,在二者中開發員自定義的代碼,便需開發員自己使用綁定變量,否則也會由於未使用綁定變量而影響性能。

五、檢查系統中sql語句共享程度及未使用綁定變量的語句的方法:
在 Oracle 8 及以上版本中,我們可以通過查詢視圖 v$sysstat 獲知系統中語句解析情況,從而瞭解綁定變量的使用情況。
select name , value
from v$sysstat
where name like 'parse count%';
其會返回兩條記錄:
parse count (hard) 爲“硬”解析,即第一次執行sql 語句時進行的解析,parse count (total) 爲所有解析次數,其由hard 與 soft 兩部分之和組成,soft 解析爲當語句在共享池中找到時,進行的權限檢查操作,其速度比 hard parse 要快得多。因而,若發現 hard parse 佔total 的比率較高,則表示語句未得到很好的共享,系統性能將受到影響。
此時,可通過檢查 v$sqlarea 視圖或 v$sqltext 視圖中所有sql語句的內容確定哪些語句未使用綁定變量,並由開發員相應進行修改。

從 v$sqlarea 查看 sql 語句的方法爲,
select SQL_TEXT, EXECUTIONS , PARSE_CALLS
from v$sqlarea
where 限制條件;
其只能查看 sql 語句的前1000個字節。若有超過1000字節的sql語句,則應通過v$sqltext 視圖查看。

select sql_text, piece, hash_value
from v$sqltext
where 限制條件
order by hash_value, piece;
其爲按每行64字節分佈,piece爲行號。
爲了不影響性能,一般爲先將某一時間點的 v$sqlarea 的內容複製到一個臨時表中,再對該表中記錄進行分析。
在 Oracle 7 中,只能從 v$sysstat 中查出所有的解析計數,但仍可從 v$sqlarea 及 v$sqltext 中查出未使用綁定變量的語句並進行修改。


摘自:http://www.fanqiang.com/a4/b4/20011110/0810001555.html
作者:趙華良
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章