Oracle-Soft Parse/Hard Parse/Soft Soft Parse解读
概述
在Oracle中存在兩種類型的SQL語句:
一類為 DDL語句(數據定義語言)CREATE,DROP,ALTER,他們是從來不會共享使用的,也就是每次執行都需要進行硬解析。
一類就是DML語句(數據操縱語言)INSERT,UPDATE,DELETE,SELECT,他們會根據情況選擇要么進行硬解析,要么進行軟解析。
當發布一條DML SQL或PL/SQL命令時,Oracle會自動尋找該命令是否存在于共享池中來決定對當前的語句使用硬解析或軟解析。
解析過程
硬/軟解析過程
a.SQL代碼的語法(語法的正確性)及語義檢查(對象的存在性與權限)。
b.將SQL代碼的文本進行哈希得到哈希值。
c.如果共享池中存在相同的哈希值,則對這個命令進一步判斷是否進行軟解析,否則到e步驟。
d.對于存在相同哈希值的新命令行,其文本將與已存在的命令行的文本逐個進行比較。這些比較包括大小寫,字符串是否一致,空格,注釋等,如果一致,則對其進行軟解析,轉到步驟f.否則到d步驟。
e.硬解析,生成執行計劃。
f.執行SQL代碼,返回結果。
軟軟解析過程
要完全理解軟軟解析先要理解游標的概念,當執行SQL時,首先要打開游標,執行完成后,要關閉游標,游標可以理解為SQL語句的一個句柄。
在執行軟軟解析之前,首先要進行軟解析,MOS上說執行3次的SQL語句會把游標緩存到PGA,這個游標一直開著,當再有相同的SQL執行時,則跳過解析的所有過程直接去取執行計劃。
實際上是當設置了session_cursor_cache這個參數之后,Cursor被直接Cache在當前Session的PGA中的,在解析的時候只需要對其語法分析、權限對象分析之后就可以轉到PGA中查找了,如果發現完全相同的Cursor,就可以直接去取結果了,也就就是實現了 Soft Soft Parse.
解析過程分析
語法檢測
判斷一條SQL語句的語法是否符合SQL的規范,比如執行:
SQL> selet * from emp;我們就可以看出由于Select關鍵字少了一個“c”,這條語句就無法通過語法檢驗的步驟了。
語義及權限檢查
語法正確的SQL語句在解析的第二個步驟就是判斷該SQL語句所訪問的表及列是否準確?用戶是否有權限訪問或更改相應的表或列? 比如如下語句:
SQL> select * from emp;select * from emp*ERROR at line 1:ORA-00942: table or view does not exist由于查詢用戶沒有可供訪問的emp對象,因此該SQL語句無法通過語義檢查。
解析的2個步驟
1. 驗證SQL語句是否完全一致
Oracle將會對傳遞進來的SQL語句使用HASH函數運算得出HASH值,再與共享池中現有語句的HASH值進行比較看是否一一對應。現有數據庫中SQL語句的HASH值我們可以通過訪問v$sql、v$sqlarea、v$sqltext等數據字典中的HASH_VALUE列查詢得出。
如果SQL語句的HASH值一致,那么ORACLE事實上還需要對SQL語句的語義進行再次檢測,以決定是否一致。那么為什么Oracle需要再次對語句文本進行檢測呢?不是SQL語句的HASH值已經對應上了?事實上就算是SQL語句的HASH值已經對應上了,并不能說明這兩條SQL語句就已經可以共享了。
在判斷是否使用硬解析時,所參照的對象及schema應該是相同的,如果對象相同,而schema不同,則需要使用硬解析,生成不同的執行計劃.
SQL> select owner,table_name from dba_tables where table_name like 'EMP%';OWNER TABLE_NAME ------------------------------ ------------------------------ ZMC EMP CC EMPEMP –兩個對象的名字相同,當所有者不同。
zmc@entel> select * from tb_obj;cc@entel> select * from tb_obj;由于查詢的對象不同,是無法共享的,此時兩者都需要使用硬解析以及走不同的執行計劃.
可以進一步查詢v$sql_shared_cursor以得知SQL為何不能共享的原因:
select address,auth_check_mismatch,translation_mismatch,optimizer_mismatchfrom v$sql_shared_cursorwhere address in ( select addressfrom v$sqlwhere upper(sql_text) like 'SELECT * FROM EMP%'); ADDRESS A T O---------------- ----- -- -- 2769AE64 N N N2769AE64 Y Y N說明:
TRANSLATION_MISMATCH 表示SQL游標涉及到的數據對象是不同的;
AUTH_CHECK_MISMATCH 表示對同樣一條SQL語句轉換是不匹配的。
optimizer_mismatch 表示會話的優化器環境是不同的。
2. 驗證SQL語句執行環境是否相同
比如同樣一條SQL語句,一個查詢會話加了/*+ first_rows */的HINT,另外一個用戶加/*+ all_rows */的HINT,他們就會產生不同的執行計劃,盡管他們是查詢同樣的數據。
通過如上檢查以后,如果SQL語句是一致的,那么就會重用原有SQL語句的執行計劃和優化方案,也就是我們通常所說的軟解析。如果SQL語句沒有找到同樣的副本,那么就需要進行硬解析了。
Oracle根據提交的SQL語句再查詢相應的數據對象是否有統計信息。如果有統計信息的話,那么CBO將會使用這些統計信息產生所有可能的執行計劃(可能多達成千上萬個)和相應的Cost,最終選擇Cost最低的那個執行計劃。如果查詢的數據對象無統計信息,則按RBO的默認規則選擇相應的執行計劃。這個步驟也是解析中最耗費資源的,因此我們應該極力避免硬解析的產生。至此,解析的步驟已經全部完成,Oracle將會根據解析產生的執行計劃執行SQL語句和提取相應的數據。
不能使用軟解析的情形
1.下面的三個查詢語句,不能使用相同的共享SQL區。盡管查詢的表對象使用了大小寫,但Oracle為其生成了不同的執行計劃
select * from emp;select * from Emp;select * from EMP;2.類似的情況,下面的查詢中,盡管其where子句empno的值不同,Oracle同樣為其生成了不同的執行計劃
select * from emp where empno=7369select * from emp where empno=7788這種情況使用綁定變量可以優化
3.在判斷是否使用硬解析時,所參照的對象及schema應該是相同的,如果對象相同,而schema不同,則需要使用硬解析,生成不同的執行計劃
硬解析的弊端
硬解析即整個SQL語句的執行需要完完全全的解析,生成執行計劃。而硬解析,生成執行計劃需要耗用CPU資源,以及SGA資源。
在此不得不提的是對庫緩存中閂(latch)的使用。閂是鎖的細化,可以理解為是一種輕量級的串行化設備。當進程申請到閂后,則這些閂用于保護共享內存的數在同一時刻不會被兩個以上的進程修改。
在硬解析時,需要申請閂的使用,而閂的數量在有限的情況下需要等待。大量的閂的使用由此造成需要使用閂的進程排隊越頻繁,性能則逾低下。
硬解析的改進方法
1 .更改參數cursor_sharing
參數cursor_sharing決定了何種類型的SQL能夠使用相同的SQLAREA
CURSOR_SHARING = { SIMILAR | EXACT | FORCE }
EXACT –只有當發布的SQL語句與緩存中的語句完全相同時才用已有的執行計劃。(默認EXACT )
FORCE –如果SQL語句是字面量,則迫使Optimizer(優化器)始終使用已有的執行計劃,無論已有的執行計劃是不是最佳的。
SIMILAR –如果SQL語句是字面量,則只有當已有的執行計劃是最佳時才使用它,如果已有執行計劃不是最佳則重新對這個SQL語句進行分析來制定最佳執行計劃
可以基于不同的級別來設定該參數,如ALTER SESSION, ALTER SYSTEM
查詢當前的CURSOR_SHARING的值
Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 SQL> show parameter CURSOR_SHARING NAME TYPE VALUE ------------------------------------ ----------- ------------ cursor_sharing string EXACT相當于
select * from v$parameter a where a.NAME like '%cursor_sharing%';SQL>alter system set cursor_sharing=’similar’; –將參數cursor_sharing的值更改為similar 注意當該參數設置為similar,會產生不利的影響
2.使用綁定變量
使用了Bind Var能提高性能主要是因為這樣做可以盡量避免不必要的硬分析(Hard Parse)而節約了時間,同時節約了大量的CPU資源。
當一個Client提交一條Sql給Oracle后,Oracle 首先會對其進行解析(Parse),然后將解析結果提交給優化器(Optimiser)來進行優化而取得Oracle認為的最優的Query Plan,然后再按照這個最優的Plan來執行這個Sql語句(當然在這之中如果只需要軟解析的話會少部分步驟)。
但是,當Oracle接到 Client提交的Sql后會首先在共享池(Shared Pool)里面去查找是否有之前已經解析好的與剛接到的這一個Sql完全相同的Sql(注意這里說的是完全相同,既要求語句上的字符級別的完全相同,又要求涉及的對象也必須完全相同)。當發現有相同的以后解析器就不再對新的Sql在此解析而直接用之前解析好的結果了。這里就節約了解析時間以及解析時候消耗的CPU資源。尤其是在OLTP中運行著的大量的短小Sql,效果就會比較明顯了。因為一條兩條Sql的時間可能不會有多少感覺,但是當量大了以后就會有比較明顯的感覺了。
綁定變量要求變量名稱,數據類型以及長度是一致,否則無法使用軟解析
綁定變量(bindvariable)是指在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使用綁定變量時要求不同的會話中使用了相同的回話環境,以及優化器的規則等。
使用綁定變量的栗子 (軟解析/軟軟解析)
測試數據:
create table xgj_test(x_id int ); insert into xgj_test(x_id) values (1); insert into xgj_test(x_id) values (2); insert into xgj_test(x_id) values (3); insert into xgj_test(x_id) values (4); insert into xgj_test(x_id) values (5); commit ;軟解析:
sql command窗口:
SQL> var xid number; SQL> exec :xid:=1;PL/SQL procedure successfully completed xid --------- 1SQL> select * from xgj_test where x_id=:xid; X_ID --------------------------------------- 1 xid --------- 1SQL> exec :xid:=2;PL/SQL procedure successfully completed xid --------- 2SQL> select * from xgj_test where x_id=:xid; X_ID --------------------------------------- 2 xid --------- 2SQL> exec :xid:=3;PL/SQL procedure successfully completed xid --------- 3SQL> select * from xgj_test where x_id=:xid; X_ID --------------------------------------- 3 xid --------- 3SQL> exec :xid:=4;PL/SQL procedure successfully completed xid --------- 4SQL> select * from xgj_test where x_id=:xid; X_ID --------------------------------------- 4 xid --------- 4SQL> exec :xid:=5;PL/SQL procedure successfully completed xid --------- 5SQL> select * from xgj_test where x_id=:xid; X_ID --------------------------------------- 5 xid --------- 5SQL>查看解析次數
軟軟解析:
beginfor i in 1..5 loopexecute immediate ' select * from xgj_test where x_id=:i' using i;end loop; end;比較軟解析和軟軟解析的解析次數
使用綁定變量的栗子 (軟軟解析)
create table xiaogongjiang(col int); --創建表txiaogongjiangcreate or replace procedure proc1 as --創建存儲過程proc1使用綁定變量來插入新記錄beginfor i in 1 .. 10000loopexecute immediate 'insert into xiaogongjiang values(:n)' using i;end loop;--提交commit;end proc1; SQL> create table xiaogongjiang(col int); --創建表txiaogongjiangTable createdSQL> SQL> create or replace procedure proc1 --創建存儲過程proc1使用綁定變量來插入新記錄......... Warning: Procedure created with compilation errors當有錯誤時,可以通過show error來顯示錯誤 SQL> show error Errors for PROCEDURE ZMC.PROC1:LINE/COL ERROR -------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 2/3 PLS-00103: Encountered the symbol "" when expecting one of the following............ SQL> SQL> create or replace procedure proc1 as --創建存儲過程proc1使用綁定變量來插入新記錄2 begin3 for i in 1 .. 100004 loop5 execute immediate 'insert into xiaogongjiang values(:n)' using i;6 end loop;--提交commit;7 end proc1;8 /Procedure createdSQL>執行存過之前,我們先查詢下v$sql中的內容:
select * from v$sql a where a.SQL_TEXT like 'insert into xiaogongjiang%';執行存過
SQL> exec proc1PL/SQL procedure successfully completed時長:
再次查詢
select * from v$sql a where a.SQL_TEXT like 'insert into xiaogongjiang%';未使用綁定變量的栗子 (硬解析)
create table xiaogongjiang2(col int); --創建表xiaogongjiang2create or replace procedure proc2 --創建存儲過程proc2,未使用綁定變量,因此每一個SQL插入語句都會硬解析as beginfor i in 1 .. 10000 loop execute immediate 'insert into xiaogongjiang2 values('||i||')'; end loop; --提交commit; end proc2;執行存過:
SQL> exec proc2PL/SQL procedure successfully completed時長:
重新查詢
select * from v$sql a where a.SQL_TEXT like 'insert into xiaogongjiang2%';每一條都是一個硬解析,也耗時了3.7S , 使用綁定變量耗時0.4S…..
在未使用綁定變量的情形下,不論是解析次數,閂使用的數量,隊列,分配的內存,庫緩存,行緩存遠遠高于綁定變量的情況。因此盡可能的使用綁定變量避免硬解析產生所需的額外的系統資源。
查看解析次數
select sql_text, s.PARSE_CALLS, loads, executionsfrom v$sql swhere sql_text like 'insert into xiaogongjiang%'order by 1, 2, 3, 4;結合栗子
create table xgj(col int); --xgj create or replace procedure proc1 as --創建存儲過程proc1使用綁定變量來插入新記錄beginfor i in 1 .. 100loopexecute immediate 'insert into xgj values(:n)' using i;end loop;--提交commit;end proc1; >exec proc1 PL/SQL procedure successfully completed上面的栗子
字段解釋:
PARSE_CALLS 解析的次數
LOADS 硬解析的次數
EXECUTIONS 執行的次數
綁定變量的優點
減少SQL語句的硬解析,從而減少因硬解析產生的額外開銷(CPU,Shared pool,latch)。其次提高編程效率,減少數據庫的訪問次數。
綁定變量的缺點
優化器就會忽略直方圖的信息,在生成執行計劃的時候可能不夠優化。SQL優化相對比較困難。
總結
1.盡可能的避免硬解析,因為硬解析需要更多的CPU資源,閂等。
2.cursor_sharing參數應權衡利弊,需要考慮使用similar與force帶來的影響。
3.盡可能的使用綁定變量來避免硬解析
總結
以上是生活随笔為你收集整理的Oracle-Soft Parse/Hard Parse/Soft Soft Parse解读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle-PROCEDURE权限解读
- 下一篇: Oracle-知识结构漫谈