1、 什麼是綁定變量
綁定變量(bind variable) :
select * from emp where empno=:empno;
是用戶放入查詢中的佔位符,它會告訴Oracle「我會隨後爲這個變量提供一個值,如今須要生成一個方案,但我實際執行語句的時候,會提供應該使用的實際值」。
實質就是用於替代sql語句中常量的替代變量。綁定變量可以使得每次提交的sql語句都徹底同樣。算法
2、 爲何使用綁定變量
使用綁定變量能夠減小硬語法分析,優化共享池的使用。在oracle 中,對於一個提交的sql語句,存在兩種可選的解析過程, 一種叫作硬解析,一種叫作軟解析。
當一個sql語句提交後,oracle會首先檢查一下共享緩衝池裏有沒有與之徹底相同的語句,若是有的話只須執行軟分析便可,不然就得進行硬分析。
一個硬解析須要經分析、解析、安全檢查 、制定執行路徑、優化訪問計劃等等許多的步驟。需消耗大量的cpu及資源。
舉個例子,要查詢編號爲001的兒童,下面兩種寫法均可以實現:
select * from t_child where childid=’001’;//不使用綁定變量
select * from t_child where childid =: childid;//使用綁定變量
可是實際應用中常常是查詢編號爲001的兒童一次之後,有可能不再用;接着你有可能查詢兒童’002’,而後查詢’003’等等。這樣每次查詢都是新的查詢,都須要硬解析;
而第二個查詢語句提供了綁定變量: childid,它的值在查詢執行時提供,查詢經 過一次編譯後,查詢方案存儲在共享池中,能夠用來檢索和重用;在性能和伸縮性方面,這二者的差別是巨大的,甚至是驚人的;
若不使用綁定變量,每一個查詢的條件不一樣致使共享池中SQL語句數量太多,重用性極低,加速了SQL語句的老化,致使共享池碎片過多。 共享池中不一樣的SQL語句數量巨大,根據LRU原則,一些語句逐漸老化,最終被清理出共享池;這樣就致使shared_pool_size 裏面命中率降低,共享池碎片增多,可用內存空間不足。而爲了維護共享池內部結構,須要使用latch,一種內部生命週期很短的lock,這將使用大量的cpu 資源,使得性能急劇降低。
不使用綁定變量違背了oracle 的shared pool 的設計的原則,違背了這個設計用來共享的思想。sql
3、 如何使用綁定變量數據庫
public DataSet GetDataTable(T_child entity) { ArrayList parmlist = new ArrayList(); ArrayList valuelist = new ArrayList(); String sql = "select * from t_child where childid =: childid"; parmlist.Add("childid"); valuelist.Add(entity.Childid); DataSet ds = SqlHelper(sql, dbName, valuelist, parmlist, ref errorMsg); return ds; }
調用如下方法:安全
public static DataSet SqlHelper(string query, string dataBaseName, ArrayList bllist, ArrayList pamlist, ref string returnMessage) { AdoHelper adoHelper = null; try { adoHelper = DatabaseConnectEntity.CreateHelper(dataBaseName); IDataParameter[] parameters = new IDataParameter[bllist.Count]; if (adoHelper._dbFactory.DatabaseType == DatabaseType.DB_Oracle) { ArrayList paramlist = new ArrayList(); for (int i = 0; i < bllist.Count; i++) { OracleParameter parm; string paramvalue = ""; if (bllist[i] == null) { parm = new OracleParameter(pamlist[i].ToString(), null); } else { paramvalue = bllist[i].ToString(); if (bllist[i].GetType().ToString() == "System.DateTime") { parm = new OracleParameter(pamlist[i].ToString(), OracleType.DateTime); parm.Value = paramvalue.Trim(); } else { parm = new OracleParameter(pamlist[i].ToString(), paramvalue.Trim()); } } paramlist.Add(parm); } paramlist.CopyTo(parameters, 0); } else { returnMessage = "非ORACLE數據庫不能執行此存儲過程!"; return null; } DataSet ds = adoHelper.ExecuteDataSet(CommandType.Text, query, parameters); return ds; } catch (Exception ex) { returnMessage = "查詢失敗!" + ex.ToString(); return null; } finally { adoHelper.Close(); } }
4、 綁定變量使用限制條件
在對建有索引的字段(包括字段集),且字段(集)的集的勢很是大時,使用綁定變量可能會致使沒法選擇最優的查詢計劃,於是會使查詢效率很是低。
集的勢很是大【即傾斜性很嚴重 】,如:一個索引字段,總記錄數有1000條,有A值的有900條;B值50條;C值50條,那麼咱們就說這個字段的集的勢很大。固然這個集的勢的算法比較複雜,他跟查詢條件、是否建索引等都有關係。好比:若全表掃描:集的勢=記錄數;索引掃描,查詢條件「=」:集的勢=記錄數/字段上的惟一值數 ;
那麼爲何說集的勢大時使用綁定變量反而會時查詢效率變低呢?
由於Oracle在執行SQL語句時,會計算各個訪問路徑的代價,採用最小代價的訪問路徑做爲語句的執行計劃。若第一次查詢的條件恰好是索引字段中記錄最多的值,那麼這個索引掃描成本就很是高,根據分析會使用全表掃描,並將這個查詢計劃保存到共享池中,而當查詢其餘值時成本很低,但因爲採用綁定變量,再也不進行硬解析,也就是不去分析採用什麼執行計劃,而是直接使用以前的這個查詢計劃,這樣會致使沒法選擇最優的查詢計劃。
對於隔至關一段時間才執行一次的sql語句,利用綁定變量的好處會被不能有效利用優化器而抵消。
oracle