SQL -- 判斷測試SQL爲軟/硬解析(Oracle)

前言:本人能力有限,本文部分參考。

執行SQL是軟解析、硬解析?

 

理論知識:(參考博客leshami

Oracle 硬解析與軟解析是我們經常遇到的問題,什麼情況會產生硬解析,什麼情況產生軟解析,又當如何避免硬解析?下面的描述將給出軟硬解析的產生,以及硬解析的弊端和如何避免硬解析的產生。(其實理論說起來不難,難的是開發讓你證明。頭皮發麻)

一、SQL語句的執行過程

    當發佈一條SQL或PL/SQL命令時,Oracle會自動尋找該命令是否存在於共享池中來決定對當前的語句使用硬解析或軟解析。

    通常情況下,SQL語句的執行過程如下:

    a.SQL代碼的語法(語法的正確性)及語義檢查(對象的存在性與權限)。

    b.將SQL代碼的文本進行哈希得到哈希值。

    c.如果共享池中存在相同的哈希值,則對這個命令進一步判斷是否進行軟解析,否則到e步驟。

    d.對於存在相同哈希值的新命令行,其文本將與已存在的命令行的文本逐個進行比較。這些比較包括大小寫,字符串是否一致,空格,註釋等,如果一致,則對其進行軟解析,轉到步驟f。否則到e步驟。

    e.硬解析,生成執行計劃。

    f.執行SQL代碼,返回結果。

      
二、硬解析的弊端

        硬解析即整個SQL語句的執行需要完完全全的解析,生成執行計劃。而硬解析,生成執行計劃需要耗用CPU資源,以及SGA資源。在此不得不提的是對庫緩存中閂的使用。閂是鎖的細化,可以理解爲是一種輕量級的串行化設備。當進程申請到閂後,則這些閂用於保護共享內存的數在同一時刻不會被兩個以上的進程修改。在硬解析時,需要申請閂的使用,而閂的數量在有限的情況下需要等待。大量的閂的使用由此造成需要使用閂的進程排隊越頻繁,性能則逾低下。
 

三、編碼硬解析的改進方法

    1.更改參數cursor_sharing 參數

        cursor_sharing決定了何種類型的SQL能夠使用相同的SQL area (PS:不建議調整)

        CURSOR_SHARING = { SIMILAR | EXACT | FORCE } 

                 EXACT    --只有當發佈的SQL語句與緩存中的語句完全相同時才用已有的執行計劃。

                 FORCE      --如果SQL語句是字面量,則迫使Optimizer始終使用已有的執行計劃,無論已有的執行計劃是不是最佳的。 

                SIMILAR    --如果SQL語句是字面量,則只有當已有的執行計劃是最佳時才使用它,如果已有執行計劃不是最佳則重新對這個SQL

                               --語句進行分析來制定最佳執行計劃。可以基於不同的級別來設定該參數,

                                      如ALTER SESSION, ALTER SYSTEM

 

    2.使用綁定變量(建議使用)

        綁定變量要求變量名稱,數據類型以及長度是一致,否則無法使用軟解析

        綁定變量(bind variable)是指在DML語句中使用一個佔位符,即使用冒號後面緊跟變量名的形式,如下

            select * from emp where empno=7788    --未使用綁定變量

            select * from emp where empono=:eno   --:eno即爲綁定變量

        在第二個查詢中,變量值在查詢執行時被提供。該查詢只編譯一次,隨後會把查詢計劃存儲在一個共享池(庫緩存)中,以便以後獲取和重用這個查詢計劃。下面使用了綁定變量,但兩個變量其實質是不相同的,對這種情形,同樣使用硬解析

            select * from emp where empno=:eno;

            select * from emp where empno=:emp_no

     使用綁定變量時要求不同的會話中使用了相同的回話環境,以及優化器的規則等。
 

 

 綁定變量優點

            減少SQL語句的硬解析,從而減少因硬解析產生的額外開銷(CPU,Shared pool,latch)。其次提高編程效率,減少數據庫的訪問次數。

 綁定變量缺點

            優化器就會忽略直方圖的信息,在生成執行計劃的時候可能不夠優化。SQL優化相對比較困難

六、總結

    1.儘可能的避免硬解析,因爲硬解析需要更多的CPU資源,閂等。

    2.cursor_sharing參數應權衡利弊,需要考慮使用similarforce帶來的影響。

    3.儘可能的使用綁定變量來避免硬解析。



 

理論知識補充結束,下面記錄一下頭皮發麻的證明過程。

截圖 1-1

註釋:一般我們都是希望開飯是使用綁定變量的。

        簡要解釋一下下面的圖片的含義。圖中1-3行爲使用綁定綁定變量,但是遞歸次數少於總執行數。主要因爲可能多次相同的語句且在共享遊標還未失效的情況下,也是不需要硬解析的。

        圖中第四行使用了綁定變量但是仍然有79次的硬解析

--以下是查詢SQL  
 SELECT SQL_TEXT,--執行的SQL文本
       sql_id,
       last_active_time, --可以大概過濾一下
       EXECUTIONS 總執行次數,
       PARSE_CALLS AS "遞歸調用/硬解析" --這個是遞歸調用解析總和,不能一概而論需要自己分析
                    FROM v$SQLstats 
                    WHERE SQL_TEXT LIKE 'SELECT PERMISSION_ID%FROM UI_Permission%WHERE RESOURCE_ID =%UNION%SELECT PERMISSION_ID%FROM UI_Permission%WHERE UI_Permission.RESOURCE_ID IN%'
                     and last_active_time >to_date('25/06/2019 8:50','dd/mm/yyyy HH24:MI') 
                     order by 4 desc;

另一個角度(遊標)分析  參考博客

1,Shared Cursor
Oracle裏的第一種類型的Cursor就是Shared Cursor。 它是存在Shared Pool裏,Shared Pool 是SGA裏的裏的一塊內存區域,Shared Pool(Library Cache & Data Dict Cache)。 Library Cache緩存的是剛剛執行過的SQL語句和PL/SQL語句(procedure,function, package and trigger)所對應的執行計劃,解析數(parse tree).Pcode,Mcode等對象。緩存在庫緩存中的對象我們稱它爲庫緩存對象(Library Cache Object). Oracle數據庫中的Shared Cursor又細分爲Parent Cursor(父遊標)和Child Cursor(子游標). 這兩種類型。我們可以通過查詢V$SQLAREA和 V$SQL 來查看當前緩存中的Parent Cursor和 Child Cursor。其中V$SQLAREA用於查看Parent Cursor, V$SQL用於查看Child Cursor. 在ORACLE數據庫裏,任意一個目標SQL 一定會同時對應兩個Shared Cursor,其中一個是Parent Cursor,另外一個是Child Cursor. Parent Cursor會存儲該SQL 的SQL 文本,而該SQL 真正的可以被重用的解析數和執行計劃則存儲在Child Cursor中。
2,Session Cursor
Oracle裏的第二種類型的Cursor就是Session Cursor。它是當前Session解析和執行SQL的載體,換句話說,Session Cursor用於在當前Session中的解析和執行SQL,它和Shared Cursor的區別是,它是緩存在PGA中,而不是像Shared Cursor那樣緩存在SGA的庫緩存裏。
Session Cursor與Session是一一對應的,不同的session的Session Cursor直接沒有辦法共享,這個和Shared Cursor有本質的區別。Session Cursor是有生命週期的,每個session都在使用的過程中都至少會經歷一場(open,parse,bind,execute,fetch and Close)中的一個或者多個階段。用過的Session Cursor不一定緩存在對應的Session 的PGA中,這取決於Session_cached_cursor的值是否大於0.Oracle在解析和執行目標SQL時,會先去當前的SESSION的PGA中找是否有匹配的緩存的Session Cursor.當第一次解析和執行目標SQL時(顯然是硬解析),當前SESSION的PGA中肯定不存在匹配的SESSION CURSOR,這個時候ORACLE 會新生成一個Session Cursor和一對Shared Cursor(即Parent Cursor 和 Child Cursor),這其中的Shared Cursor會存儲能被所有Session共享,重用的內容(比如目標SQL的解析樹,執行計劃等),而Session Cursor則會經歷一次open,parse,bind,execute,fetch和close中的一個或多個階段。顯然一個Session Cursor 只能對應一個Shared Cursor, 而一個Shared Cursor卻可以同時對應多個Session Cursor.
 

 

========================================================================================

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章