Oracle中解析SQL語句的過程

來源:互聯網
上載者:User

為了將使用者寫的SQL文本轉化為Oracle認識的且可執行檔語句,這個過程就叫做解析過程。解析分為硬解析和軟解析。一條SQL語句在第一次被執行時必須進行硬解析。

當用戶端發出一條SQL語句(也可以是一個預存程序或者一個匿名PL/SQL塊)進入shared pool時(注意,我們從前面已經知道,Oracle對這些SQL不叫做SQL語句,而是稱為遊標。因為Oracle在處理SQL時,需要很多相關的輔助資訊,這些輔助資訊與SQL語句一起組成了遊標), Oracle首先將SQL文本轉化為ASCII值,然後根據hashFunction Compute其對應的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語句進行文法檢查,看是否有文法錯誤。比如沒有寫from、select拼字錯誤等。如果存在文法錯誤,則退出解析過程。到資料字典裡校正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

查看本欄目更多精彩內容:http://www.bianceng.cnhttp://www.bianceng.cn/database/Oracle/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.