熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Oracle >> 正文

Sql語句解析過程

2013-11-13 22:16:34  來源: Oracle 

  為了將用戶寫的SQL文本轉化為Oracle認識的且可執行的語句這個過程就叫做解析過程解析分為硬解析和軟解析一條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語句

  如果不存在則需要按照我們前面所描述的獲得shared pool latch然後在shared pool中的可用chunk鏈表(也就是bucket)上找到一個可用的chunk之後釋放shared pool latch在獲得了chunk以後這塊chunk就可以認為是進入了library cache接下來進行硬解析過程硬解析包括以下幾個步驟

  對SQL語句進行文法檢查看是否有文法錯誤比如沒有寫fromselect拼寫錯誤等如果存在文法錯誤則退出解析過程

  到數據字典裡校驗SQL語句涉及的對象和列是否都存在如果不存在則退出解析過程這個過程會加載dictionary cache

  將對象進行名稱轉換比如將同名詞翻譯成實際的對象等比如select * from t中t是一個同名詞指向hrt於是Oracle將t轉換為hrt如果轉換失敗則退出解析過程

  檢查發出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 *sum(reloads)/sum(pins) Reload_Ratio from v$librarycache;

  一個父游標可以對應多個子游標子游標具體的個數可以從視圖v$sqlarea的version_count字段體現出來而每個具體的子游標則全都在視圖v$sql裡體現當具體綁定變量的值與上次綁定變量的值有較大差異(比如上次執行的綁定變量值的長度是而這次執行綁定變量的值的長度是位)時或者當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 := ;

  SQL> select object_idobject_name from sharedpool_test

  where object_id=:v_obj_id;

  OBJECT_ID       OBJECT_NAME

      

             AGGXMLIMP

  接下來定義一個字符型的綁定變量變量名與前面相同為該綁定變數賦一個字符型的值以後執行相同的查詢

  SQL> variable v_obj_id varchar();

  SQL> exec :v_obj_id := ;

  SQL> select object_idobject_name from sharedpool_test

  where object_id=:v_obj_id;

  OBJECT_ID       OBJECT_NAME

      

             AGGXMLIMP

  然後我們到視圖v$sqlarea裡找到該SQL的父游標的信息並到視圖v$sql裡找該SQL的所有子游標的信息

  SQL> select sql_textversion_count from v$sqlarea where

  sql_text like %sharedpool_test%;

  SQL_TEXT

  VERSION_COUNT

  

  

  select object_idobject_name from sharedpool_test where

  object_id=:v_obj_id         

  SQL> select sql_textchild_addressaddress from v$sql

  where sql_text like %sharedpool_test%;

  SQL_TEXT

  CHILD_ADDRESS  ADDRESS

  

  

  select object_idobject_name from sharedpool_test where

  object_id=:v_obj_id    F

  BD

  select object_idobject_name from sharedpool_test where

  object_id=:v_obj_id    FC

  BD

  從記錄父游標的視圖v$sqlarea的version_count列可以看到該SQL語句有個子游標而從記錄子游標的視圖v$sql裡可以看到該SQL文本確實有兩條記錄而且它們的SQL文本所處的地址(ADDRESS列)也是一樣的但是子地址(CHILD_ADDRESS)卻不一樣這裡的子地址實際就是子游標所對應的heap 的句柄

  由此我們也可以看到存在許多因素可能導致SQL語句不能共享常見的因素包括SQL文本大小寫不一致SQL語句的綁定變量的類型不一致SQL語句涉及的對象名稱雖然一致但是位於不同的schema下SQL的優化器模式不一致(比如添加提示修改了optimizer_mode參數等)等


From:http://tw.wingwit.com/Article/program/Oracle/201311/18653.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.