爲了將用戶寫的SQL文本轉化爲Oracle認識的且可執行的語句,這個過程就叫作解析過程。解析分爲硬解析和軟解析。一條SQL語句在第一次被執行時必須進行硬解析。sql
當客戶端發出一條SQL語句(也能夠是一個存儲過程或者一個匿名PL/SQL塊)進入shared pool時(注意,咱們從前面已經知道,Oracle對這些SQL不叫作SQL語句,而是稱爲遊標。由於Oracle在處理SQL時,須要不少相關的輔助信息,這些輔助信息與SQL語句一塊兒組成了遊標),Oracle首先將SQL文本轉化爲ASCII值,而後根據hash函數計算其對應的hash值(hash_value)。根據計算出的hash值到library cache中找到對應的bucket,而後比較bucket裏是否存在該SQL語句。session
若是不存在,則須要按照咱們前面所描述的,得到shared pool latch,而後在shared pool中的可用chunk鏈表(也就是bucket)上找到一個可用的chunk,以後釋放shared pool latch。在得到了chunk之後,這塊chunk就能夠認爲是進入了library cache。接下來,進行硬解析過程。硬解析包括如下幾個步驟。oracle
對SQL語句進行文法檢查,看是否有文法錯誤。好比沒有寫from、select拼寫錯誤等。若是存在文法錯誤,則退出解析過程。ide
到數據字典裏校驗SQL語句涉及的對象和列是否都存在。若是不存在,則退出解析過程。這個過程會加載dictionary cache。函數
將對象進行名稱轉換。好比將同名詞翻譯成實際的對象等。好比select * from t中,t是一個同名詞,指向hr.t1,因而Oracle將t轉換爲hr.t1。若是轉換失敗,則退出解析過程。測試
檢查發出SQL語句的用戶是否具備訪問SQL語句裏所引用的對象的權限。若是沒有權限,則退出解析過程。優化
經過優化器建立一個最優的執行計劃。這個過程會根據數據字典裏記錄的對象的統計信息,來計算最優的執行計劃。這一步牽涉大量數學運算,是最消耗CPU資源的。翻譯
將該遊標所產生的執行計劃、SQL文本等裝載進library cache的heap中。視頻
在硬解析的過程當中,進程會一直持有library cache latch,直到硬解析結束爲止。硬解析結束之後,會爲SQL語句產生兩個遊標,一個是父遊標,另外一個是子游標。父遊標裏主要包含兩種信息:SQL文本以及優化目標(optimizer goal)。父遊標在第一次打開時被鎖定,直到其餘全部的session都關閉該遊標後才被解鎖。當父遊標被鎖定的時候是不能被交換出library cache的,只有在解鎖之後才能被交換出library cache。父遊標被交換出內存時,父遊標對應的全部子游標也被交換出library cache。子游標包括遊標全部的信息,好比具體的執行計劃、綁定變量等。子游標隨時能夠被交換出library cache,當子游標被交換出library cache時,Oracle能夠利用父遊標的信息從新構建出一個子遊標來,這個過程叫reload。可使用下面的方式來肯定reload的比率:對象
select 100*sum(reloads)/sum(pins) Reload_Ratio from v$librarycache;
一個父遊標能夠對應多個子遊標。子游標具體的個數能夠從視圖v$sqlarea的version_count字段體現出來。而每一個具體的子游標則全都在視圖v$sql裏體現。當具體綁定變量的值與上次綁定變量的值有較大差別(好比上次執行的綁定變量值的長度是6位,而此次執行綁定變量的值的長度是200位)時或者當SQL語句徹底相同,可是所引用的表屬於不一樣的用戶時,都會建立一個新的子游標。
若是在bucket中找到了該SQL語句,則說明該SQL語句之前運行過,因而進行軟解析。軟解析是相對於硬解析而言的,若是解析過程當中,能夠從硬解析的步驟中去掉一個或多個的話,這樣的解析就是軟解析。軟解析分爲如下三種類型。
第一種是某個session發出的SQL語句與library cache裏其餘session發出的SQL語句一致。這時,該解析過程當中能夠去掉硬解析中的 和 ,可是仍然要進行硬解析過程當中的 、 、,也就是表名和列名檢查、名稱轉換和權限檢查。
第二種是某個session發出的SQL語句是該session以前發出的曾經執行過的SQL語句。這時,該解析過程當中能夠去掉硬解析中的、 、 和 這四步,可是仍然要進行權限檢查,由於可能經過grant改變了該session用戶的權限。
第三種是當設置了初始化參數session_cached_cursors時,當某個session第三次執行相同的SQL時,則會把該SQL語句的遊標信息轉移到該session的PGA裏。這樣,該session之後再執行相同的SQL語句時,會直接從PGA裏取出執行計劃,從而跳過硬解析的全部步驟。這種狀況下,是最高效的解析方式,可是會消耗很大的內存。
咱們舉一個例子來講明解析SQL語句的過程。在該測試中,綁定變量名稱相同,可是變量類型不一樣時,所出現的解析狀況。以下所示。
首先,執行下面的命令,清空shared pool裏全部的SQL語句:
SQL> alter system flush shared_pool;
而後,定義一個數值型綁定變量,併爲該綁定變數賦一個數值型的值之後,執行具體的查詢語句。
SQL> variable v_obj_id number;
SQL> exec :v_obj_id := 4474;
SQL> select object_id,object_name from sharedpool_test
where object_id=:v_obj_id;
OBJECT_ID OBJECT_NAME
---------- ---------------------------
4474 AGGXMLIMP
接下來,定義一個字符型的綁定變量,變量名與前面相同,爲該綁定變數賦一個字符型的值之後,執行相同的查詢:
SQL> variable v_obj_id varchar2(10);
SQL> exec :v_obj_id := '4474';
SQL> select object_id,object_name from sharedpool_test
where object_id=:v_obj_id;
OBJECT_ID OBJECT_NAME
---------- ---------------------------
4474 AGGXMLIMP
而後咱們到視圖v$sqlarea裏找到該SQL的父遊標的信息,併到視圖v$sql裏找該SQL的全部子游標的信息。
SQL> select sql_text,version_count from v$sqlarea where
sql_text like ‘%sharedpool_test%’;
SQL_TEXT
VERSION_COUNT
-------------------------------------------------------
select object_id,object_name from sharedpool_test where
object_id=:v_obj_id 2
SQL> select sql_text,child_address,address from v$sql
where sql_text like ‘%sharedpool_test%’;
SQL_TEXT
CHILD_ADDRESS ADDRESS
-------------------------------------------------------
select object_id,object_name from sharedpool_test where
object_id=:v_obj_id 6757F358 676B6D08
select object_id,object_name from sharedpool_test where
object_id=:v_obj_id 674440FC 676B6D08
從記錄父遊標的視圖v$sqlarea的version_count列能夠看到,該SQL語句有2個子遊標。而從記錄子游標的視圖v$sql裏能夠看到,該SQL文本確實有兩條記錄,並且它們的SQL文本所處的地址(ADDRESS列)也是同樣的,可是子地址(CHILD_ADDRESS)卻不同。這裏的子地址實際就是子游標所對應的heap 0的句柄。
由此咱們也能夠看到,存在許多因素可能致使SQL語句不能共享。常見的因素包括SQL文本大小寫不一致、SQL語句的綁定變量的類型不一致、SQL語句涉及的對象名稱雖然一致可是位於不一樣的schema下、SQL的優化器模式不一致(好比添加提示、修改了optimizer_mode參數等)等
oracle視頻教程請關注:http://down.51cto.com/4202939/up