Oracle优化09-绑定变量
思維導圖
系列博文
Oracle-綁定變量binding variable解讀
Oracle-Soft Parse/Hard Parse/Soft Soft Parse解讀
概述
綁定變量是OLTP系統中一個非常值得關注的技術點。良好的變量綁定會使OLTP系統數據庫中的SQL執行的飛快,內存效率極高。 不綁定變量有可能會使OLTP數據庫不堪負重,資源被SQL解析嚴重消耗,系統顯得緩慢。
本博文的案例基于Oracle Database 11g Enterprise Edition Release 11.2.0.4.0
SQL究竟是如何被執行的?
在介紹綁定變量之前,我們需要知道SQL究竟是如何被執行的?
當一個用戶與數據庫建立連接后,向數據庫發送SQL語句,Oracle在接到這條SQL后,首先會將這個SQL做一個Hash函數運算,得到一個Hash值,然后到共享池中尋找是否有和這個hash值匹配的SQL存在。
如果找到了,Oracle會直接使用已經存在的SQL的執行計劃去執行當前的SQL,然后將結果返回給用戶。
如果沒有找到,Oracle會認為這是一條新的SQL, 將會按照下面的順序來執行:
1 .語法分析
SQL 是否符Oracle規定的語法,如果有語法錯誤,則向用戶拋出錯誤信息
2. 語義分析
語法分析通過之后,Oracle會對這條SQL做一些對象、權限方面的檢查,查看SQL中操作的表是否存在,表中的列是否正確,用戶是否有權限操作這個對象的權限等
3 .生成執行計劃
這個過程Oracle在經過一些列的操作之后,來做出SQL最后的執行計劃,比如查看操作對象的統計信息,動態采樣等等。
如何生成執行計劃的詳細信息,可以參考10053事件
4.執行SQL
Oracle按照上一步生成的執行計劃,執行SQL,并將結果返回給用戶。
以上的這些工作,我們通常稱為硬分析(hard parse),其實是十分消耗系統資源的。 而對于相同Hash值的SQL已經存在于共享池中則稱為軟分析(soft parse)。
綁定變量 what ,why
綁定變量就起本質而言就是說把本來需要Oracle做硬分析的SQL變成了軟分析,以減少Oracle花費在SQL解析上的時間和資源。
是否采用綁定變量在資源消耗上對比
下面我們來對下同一條SQL被執行10000次,綁定變量和非綁定變量在資源消耗上的情況
采用綁定變量
打開SQL_TRACE
Connected to Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 Connected as xx@xgj##打開時間統計 SQL> set timing on;##為防止干擾信息,先手動的清空共享池中的信息(若生產環境慎重) SQL> alter system flush shared_pool;System alteredExecuted in 0.078 seconds##建表 SQL> create table t as select * from dba_objects; Table createdExecuted in 0.281 seconds##設置trace文件標識 SQL> alter session set tracefile_identifier='xgj_var_bind';Session alteredExecuted in 0 seconds##打開SQL_TRACE SQL> alter session set sql_trace=true;Session alteredExecuted in 0.015 seconds##執行SQL塊 SQL> begin2 for i in 1 .. 10000 loop3 execute immediate 'select * from t where t.object_id = :i' using i ;4 end loop;5 end;6 /PL/SQL procedure successfully completedExecuted in 0.578 seconds##關閉SQL_TRACE SQL> alter session set sql_trace=false ;Session alteredExecuted in 0 secondsSQL>對原始trace文件進行tkprof分析匯總
在Oracle服務器端獲取到trace文件后,使用tkprof進行分析匯總,查看
oracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$ls *xgj_var_bind* cc_ora_32363_xgj_var_bind.trc cc_ora_32363_xgj_var_bind.trmoracle@entel1:[/oracle/diag/rdbms/cc/cc/trace]$tkprof cc_ora_32363_xgj_var_bind.trc xgj_var_bind.txt sys=noTKPROF: Release 11.2.0.4.0 - Development on Sat Dec 17 21:13:11 2016Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.我們截取分析匯總后的關鍵部分來看
整個過程加上產生的遞歸SQL,我們可以看到整個語句的:
ALL NON-RECURSIVE STATEMENTS + ALL RECURSIVE STATEMENTS
- 執行時間(elapsed):0.48+0.10 = 0.58 (和剛才輸出的時間大致一致)
- CPU時間(cpu):0.48+0.09=0.57
- 分析次數(parse):8+2=10
- 執行次數(execute):9+10017=10025
不采用綁定變量
SQL> set timing on ; SQL> alter session set tracefile_identifier='xgj_var_unbind';Session alteredExecuted in 0.016 seconds SQL> alter session set sql_trace=true;Session alteredExecuted in 0.016 seconds SQL> begin2 for x in 1 .. 10000 loop3 execute immediate 'select * from t where t.object_id ='||x;4 end loop;5 end;6 /PL/SQL procedure successfully completedExecuted in 16.672 seconds -----耗時很長SQL>執行tkprof分析匯總
查看xgj_var_unbind.txt關鍵部分
………… 中間省略一萬萬字
可以看到 每一條都是hard parse,非常消耗系統資源,耗時很長。
同樣的我們統計下執行信息:
ALL NON-RECURSIVE STATEMENTS + ALL RECURSIVE STATEMENTS
- 執行時間(elapsed):1.28+15.38 =16.66
- CPU時間(cpu):1.22+15.31
- 分析次數(parse): 3+20000
- 執行次數(execute):4+20000
通過對比我們可以發現,在OLTP系統中,使用綁定變量的SQL資源消耗要與那遠少于未綁定變量SQL的資源消耗,SQL執行的次數越多,差距越明顯。
未綁定變量SQL的資源主要消耗在產生的遞歸SQL上,這些SQL主要是對SQL語句做hard parse時使用的。
試想,當一個數據庫有成千上萬甚至更多的用戶同時執行這樣的SQL,而ORACLE只做一次硬分析,后面相同的SQL只執行SQL的執行操作,勢必將大大減輕數據庫的資源開銷。
這就是綁定變量的由來,它并不神秘,不過是拿一個變量來代替謂詞常量,讓ORACLE每次對用戶發送的SQL做hash運算,運算出相同的hash值,于是Oracle便將這些SQL看做同一個SQL對待而已。
OLTP和OLAP系統中是否需要綁定變量分析
如果你使用Oracle的圖形化工具DBCA創建數據庫,應該有印象,其中有一步是要求你選擇數據庫的類型是OLTP還是OLAP。 其實這就說明了OLTP和OLAP數據庫是有很大的差異的,Oracle需要知道你選擇的系統架構,以便于按照系統的架構對相應的參數值做設定,比如初始化參數。
OLTP和OLAP的請參考之前梳理的文章 Oracle-OLAP和OLTP解讀
http://blog.csdn.net/yangshangwei/article/details/52949378
OLTP栗子
數據:
SQL> drop table t;Table droppedSQL> create table t as select a.OBJECT_ID ,a.OBJECT_NAME from dba_objects a ;Table createdSQL> select count(1) from t;COUNT(1) ----------35234SQL> 循環300次,寫入更多的數據 每50次提交一次數據 SQL> begin2 for i in 1 .. 300 loop3 execute immediate 'insert into t select a.OBJECT_ID ,a.OBJECT_NAME from dba_objects a';4 if mod(i,50)=0 then5 commit;6 end if;7 end loop;8 end;9 /PL/SQL procedure successfully completedSQL> select count(1) from t;COUNT(1) ----------10605434SQL> 在object_id字段上創建索引 SQL> create index idx_t on t(object_id);Index created操作步驟
SQL> alter session set tracefile_identifier='xgj_oltp';Session alteredSQL> alter session set sql_trace =true;Session altered執行兩遍SQL ##強制走全表掃描執行計劃 SQL> select /*+ full(t)*/ * from t where object_id = 188;OBJECT_ID OBJECT_NAME ---------- ---------------------188 SQLLOG$_PKEY...........301 rows selected##讓Oracle自己選擇執行計劃 SQL> select * from t where t.object_id = 188;OBJECT_ID OBJECT_NAME ---------- ---------------------188 SQLLOG$_PKEY...........301 rows selectedSQL> alter session set sql_trace=false;Session alteredtkprof匯總分析
可以看到 全表掃描執行計劃的SQL掃描過的數據塊明顯大于使用索引執行的SQL計劃。
從trace文件中可以看到,在fetch階段,全表掃描讀取了42093多個數據塊,而走索引的,在fetch階段,僅僅讀取了308個數據塊。
OLAP栗子
OLAP系統在SQL的操作中就復雜的多,OLAP數據庫上大多數的時候運行是一些報表SQL,這些SQL經常會用到聚合查詢(比如group by),而且結果集也是非常龐大,在這種情況下,索引并不是必然的選擇,甚至有些時候全表掃描的性能會由于索引,即使相同的SQL,如果謂詞條件不同,執行計劃都可能不同
數據
SQL> create table t2(object_id, object_name) partition by range (object_id)2 (partition p1 values less than (5000),3 partition p2 values less than (15000),4 partition p3 values less than (25000),5 partition p4 values less than (maxvalue))6 as select object_id, object_name from dba_objects;Table createdSQL> SQL> begin2 for x in 1 .. 300 loop3 insert into t2 select object_id ,object_name from dba_objects ;4 if mod(x,50)=0 then5 commit;6 end if;7 end loop;8 end;9 /PL/SQL procedure successfully completedSQL> select count(1) from t2;COUNT(1) ----------10609046SQL> select count(1) from t2 partition(p1);COUNT(1) ----------1504097SQL> select count(1) from t2 partition(p2);COUNT(1) ----------2691241SQL> select count(1) from t2 partition(p3);COUNT(1) ----------0SQL> select count(1) from t2 partition(p4);COUNT(1) ----------6413708SQL> 在分區表上建立本地索引 SQL> create index idx_t_id on t2(object_id) local;Index created##對表做一次分析(cascade => true ,索引也會被一同分析) SQL> exec dbms_stats.gather_table_stats(user,'t2',cascade => true);PL/SQL procedure successfully completed操作步驟
我們使用如下命令
注釋:以上的命令,是在plsql客戶端執行的,可以支持, 但是autotrace命令,plsql并沒有很好的支持,所以我登錄到了服務器所在的主機執行的,當然也可以通過sqlplus客戶端操作。
SQL> set autotrace traceonly explain ;從結果中我們可以看到,雖然只是謂詞的不同,但是oracle卻選擇了不同的執行計劃,因為Oracle認為那樣的計劃代價最小。
結論
bind peeking
談到變量綁定,我們不得不提一下從Oracle9i開始引入的一個新的特性,叫做bind peaking ,顧名思義,就是在SQL語句硬解析的時候,Oracle會看一下當前SQL謂詞的值,以便于生成最佳的執行計劃。
需要強調的是,bind peaking 只發生在hard parse的時候,即SQL被第一次執行的時候,之后的變量將不會再做peeking.
bind peeking 并不能最終解決不同謂詞導致不同執行計劃的問題,它只能讓SQL第一次執行的時候,執行計劃更加準確,并不能幫助OLAP系統解決綁定變量導致執行計劃選擇錯誤的問題,所以,OLAP依然不應該使用綁定變量。
對于OLTP系統來講,相同的SQL重復頻率非常搞,如果優化器范湖解析SQL,勢必極大地消耗資源。 另外OLTP系統用戶請求的結果通常都是非常小,說基本上都會考慮使用索引。 bind peeking在第一次hard parse的時候獲得了一個正確的執行計劃,后面的SQL都按照這個計劃來執行,可以極大地改善系統的性能,這是由OLTP系統的特性決定的。
總結
以上是生活随笔為你收集整理的Oracle优化09-绑定变量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle优化11-10046事件
- 下一篇: Oracle优化03-Latch和等待