為什么 ExplainPlan 與RuntimePlan 會有差異

為什么預估執(zhí)行計劃與真實執(zhí)行計劃會有差異?




一、問題概要


對同一個SQL語句的ExplainPlan里顯示的預估執(zhí)行計劃與通過V$SQL_PLAN視圖獲取的Runtime Plan真實執(zhí)行計劃,偶爾會發(fā)現(xiàn)兩邊有不一致的情況,為什么呢?為什么預估執(zhí)行計劃會不準確?怎樣才能避免這種情況的發(fā)生?


二、問題解答


這是執(zhí)行計劃相關中會被經(jīng)常問道的問題,也是困擾自己很長時間的問題。希望通過下面的分析能解釋一部分原因。

對同一個SQL語句的ExplainPlan里顯示的預估執(zhí)行計劃與通過V$SQL_PLAN視圖獲取的真實執(zhí)行計劃不一致的情況,其原因要比想象的更多種多樣。


[if !supportLists]l? [endif]綁定變量窺視(Bind Peeking:Explain Plan里不會進行綁定變量窺視,但是Runtime Plan里會進行綁定變量窺視,所以,如果這種情況發(fā)生會使兩個執(zhí)行計劃會產生差異。

[if !supportLists]l? [endif]隱式轉換:Explain Plan里不會考慮綁定變量的類型,但是Runtime Plan里會考慮類型,從而有可能會根據(jù)綁定變量的類型出現(xiàn)隱式轉換,所以謂詞(Predicate)會發(fā)生變化,使得執(zhí)行計劃也會產生差異。

[if !supportLists]l? [endif]優(yōu)化器參數(shù):執(zhí)行Explain Plan的Session與Runtime Plan的Session不是同一個。如果各個Session之間存在優(yōu)化器參數(shù)差異,執(zhí)行計劃也會產生差異。

[if !supportLists]l? [endif]統(tǒng)計信息收集參數(shù):Explain Plan始終是用最新的統(tǒng)計信息產生執(zhí)行計劃,但是,Runtime Plan不一定會用最新的統(tǒng)計信息。因此也會產生執(zhí)行計劃差異。


?? ?預估執(zhí)行計劃與實際執(zhí)行計劃產生差異的原因總結為上面幾種情況,當然也有因Oracle Bug的原因也會有產生執(zhí)行計劃的差異情況。

下面通過幾個測試,加深對上面的問題的理解。


三、測試環(huán)境


Oracle 版本是 11.2.0.1的情況。


SQL> SELECT * FROMV$VERSION WHERE ROWNUM <= 1;


BANNER

--------------------------------------------------------------------------------

Oracle Database 11g

Enterprise Edition Release 11.2.0.1.0 –Production



生成表 T1,T1表有如下特點:

表名列名列類型說明

T1C1Number“1”值有10,000個,“1~10000”的值各一個,總共有10,000種值

C2Varchar2同上

之后,對列C1、C2分別生成單列索引 IDX_T1_C1 和IDX_T1_C2。



SQL> CREATE TABLET1 ( C1 INT , C2 VARCHAR2(10));


表已創(chuàng)建。


SQL> INSERT INTOT1 SELECT 1, '1' FROM DUAL CONNECT BY LEVEL <= 10000;


已創(chuàng)建10000行。


SQL> INSERT INTOT1 SELECT LEVEL, LEVEL FROM DUAL CONNECT BY LEVEL <= 10000;


已創(chuàng)建10000行。


SQL> CREATE INDEXIDX_T1_C1 ON T1(C1);


索引已創(chuàng)建。


SQL> CREATE INDEXIDX_T1_C2 ON T1(C2);


索引已創(chuàng)建。


對表T1進行統(tǒng)計信息收集。METHOD_OPT 的參數(shù)設為 ALL

COLUMNS SIZE 5 ,即,直方圖的BUCKETS個數(shù)指定為5。但是列C1和C2有 10,000個不同的值,BUCKETS個數(shù)為5的話,會生成等高直方圖(HEIGHT BALANCED)。


SQL> EXECDBMS_STATS.gather_table_stats(user,'T1', method_opt =>'FOR ALL COLUMNS SIZE5');


PL/SQL 過程已成功完成。



收集統(tǒng)計信息以后如下:


--table stats

Set linesize 100

SELECT t1.owner,

t1.TABLE_NAME,

?????? t1.num_rows,

?????? t1.SAMPLE_SIZE

FROM?? dba_tables t1

WHERE? table_name = 'T1'

AND??? t1.OWNER = user;


TABLE_NAME?? NUM_ROWS SAMPLE_SIZE

---------- ---------------------

T1????????????? 20000?????? 20000


--column stats

Set linesize 120

Col table_name formata15

Col column_nameformat a10

Col low_value formata15

Col high_value formata15


SELECT t2.TABLE_NAME,

?????? t2.COLUMN_NAME,

?????? t2.NUM_DISTINCT,

?????? t2.NUM_NULLS,

?????? t2.DENSITY,

?????? t2.LOW_VALUE,

?????? t2.HIGH_VALUE,

??????t2.HISTOGRAM

FROM?? dba_tab_columns t2

WHERE? t2.table_name = 'T1'

AND??? t2.OWNER = user;


TABLE COLUMNUM_DISTINCT NUM_NULLS DENSITY LOW_V HIGH_VALUE HISTOGRAM

----- ----------------- --------- ------- ----- ---------- --------------------

T1??? C1??????????10000???????? 0? 0.00005 C102?C302?????? HEIGHT BALANCED

T1??? C2??????????10000???????? 0? 0.00005 31???39393939?? HEIGHT BALANCED


--histogram stats

Set linesize 100

Col table_name formata20

Col column_nameformat a20

select t3.TABLE_NAME

?????? ,t3.COLUMN_NAME

?????? ,t3.ENDPOINT_NUMBER

?????? ,to_char(t3.ENDPOINT_VALUE)

from? dba_tab_histograms t3

WHERE? t3.table_name = 'T1'

AND??? t3.OWNER = user;


TABLE COLUM ENDPOINTENDPOINT_VALUE

----- ----- ----------------------

T1??? C1??????????2????????????? 1

T1??? C1??????????3?????????? 2000

T1??? C1??????????4?????????? 6000

T1??? C1??????????5????????? 10000

T1??? C2??????????2 2.544225460682

T1??? C2??????????3 2.607349087913

T1??? C2??????????4 2.814229665870

T1??? C2??????????5 2.971215519298




四、案列1:綁定變量窺視(Bind Peeking

下面我們看下,因綁定變量窺視,而引起的預估執(zhí)行計劃與實際執(zhí)行計劃不一致的情況。首先,激活綁定變量窺視功能,默認值就是TRUE。



SQL> alter sessionset "_optim_peek_user_binds" = true;


會話已更改。



首先,我們輸出預估執(zhí)行計劃。從下面可以看到,執(zhí)行計劃選擇的是索引范圍掃描(Index Range Scan)的方式。



SQL> var b1 number;

SQL> exec :b1 :=1;


PL/SQL 過程已成功完成。


SQL> explain planfor

??? select count(c2)

??? from t1

??? where c1 = :b1;


已解釋。


SQL> select * fromtable(dbms_xplan.display(null,null,'typical'));



------------------------------------------------------------------------------------------

| Id? | Operation??????????????????? | Name????? | Rows?| Bytes | Cost (%CPU)| Time???? |

------------------------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT???????????? |???????? ??|???? 1|???? 6 |???? 2??(0)| 00:00:01 |

|?? 1 |?SORT AGGREGATE????????????? |?????????? |????1 |???? 6 |??????????? |????????? |

|?? 2 |??TABLE ACCESS BY INDEX ROWID| T1???????|???? 2 |??? 12 |????2?? (0)| 00:00:01 |

|*? 3 |???INDEX RANGE SCAN?? ???????| IDX_T1_C1 |???? 2 |??????|???? 1?? (0)| 00:00:01 |

------------------------------------------------------------------------------------------


Predicate Information(identified by operation id):

---------------------------------------------------


?? 3 - access("C1"=TO_NUMBER(:B1))



綁定變量B1的實際值是“1”。T1表里值為1的記錄數(shù)將近占50%,這種情況與其選擇索引范圍掃,不如選擇全表掃(Table Full Scan)會有效率一些。但是 ExplainPlan命令不進行綁定變量的窺視,即,在創(chuàng)建預估執(zhí)行計劃的過程中,會把綁定變量的值設為未知(Uknown)來處理,不會考慮實際的綁定變量的值到底是什么。所以,ExplainPlan不關心其值是不是“1”,而只考慮Distinct Count來建立執(zhí)行計劃。

等高直方圖(HEIGHT BALANCED)存在的時候,預估行數(shù)會通過DistinctCount列進行計算。計算公式如下:


預估行數(shù) = 全部行數(shù)/ Distinct Count = 20,000 /10,000? =?2?


但是,實際執(zhí)行計劃與上面的結果完全不一樣,如下。



SQL> select /*+gather_plan_statistics */ count(c2)

??? from t1

??? where c1 = :b1;


?COUNT(C2)

----------

???? 10001


SQL> select * fromtable(dbms_xplan.display_cursor(null,null,'typical'));


---------------------------------------------------------------------------

| Id? | Operation????????? | Name | Rows? | Bytes | Cost (%CPU)| Time???? |

---------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT?? |?????|?????? |?????? |???12 (100)|????????? |

|?? 1 |?SORT AGGREGATE??? |????? |????1 |???? 6 |??????????? |????????? |

|*? 2 |??TABLE ACCESS FULL| T1?? |? 8000 | 48000 |??? 12??(0)| 00:00:01 |

---------------------------------------------------------------------------


Predicate Information(identified by operation id):

---------------------------------------------------


?? 2 - filter("C1"=:B1)


可以看到,使用了綁定變量窺視,即,優(yōu)化器在創(chuàng)建執(zhí)行計劃前讀取了綁定變量的實際的值(進行是窺視)。之后,參考綁定變量的值來創(chuàng)建執(zhí)行計劃。這個例子,使用了值“1”來創(chuàng)建了執(zhí)行計劃。所以,預估行數(shù)從ExplainPlan里的2 變成了8000。其原因如下:

?? 預估行數(shù)=?值“1”的buckets 數(shù) * buckets 的高度

????????????? =?2 *(20000 / 5 )=?8000

實際行數(shù)為10,001,預估值與實際值相當接近了。

使用DBMS_XPLAN.DISPLAY_CURSOR函數(shù)的時候,參數(shù)里如果加上 +PEEKED_BBINDS的話,執(zhí)行計劃里可以看到綁定變量窺視的值。



SQL> select /*+gather_plan_statistics */ count(c2)

?? ??fromt1

??? ?wherec1 = :b1;


?COUNT(C2)

----------

???? 10001


SQL> select * from

table(dbms_xplan.display_cursor(null,null,'all +peeked_binds'));



---------------------------------------------------------------------------

| Id? | Operation????????? | Name | Rows? | Bytes | Cost (%CPU)| Time???? |

---------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT?? |?????|?????? |?????? |???12 (100)|????????? |

|?? 1 |?SORT AGGREGATE??? |????? |????1 |???? 6 |??????????? |????????? |

|*? 2 |??TABLE ACCESS FULL| T1?? |? 8000 | 48000 |??? 12??(0)| 00:00:01 |

---------------------------------------------------------------------------


Query Block Name /Object Alias (identified by operation id):

-------------------------------------------------------------


?? 1 - SEL$1

?? 2 - SEL$1 / T1@SEL$1


Peeked Binds(identified by position):

--------------------------------------


?? 1 - :B1 (NUMBER): 1


Predicate Information(identified by operation id):

---------------------------------------------------


?? 2 - filter("C1"=:B1)


Column ProjectionInformation (identified by operation id):

-----------------------------------------------------------


?? 1 - (#keys=0) COUNT("C2")[22]

?? 2 - "C2"[VARCHAR2,10]



綁定變量窺視(Binding Peeking)與綁定變量捕獲(Bind Capture)經(jīng)常弄混。綁定變量捕獲(Bind Capture)是對特定SQL里使用的綁定變量值按照固定周期放到SGA里保存的情況。最初的綁定變量窺視與綁定變量捕獲的時間是一樣,約15分鐘(900秒)后,綁定變量捕獲會再次發(fā)生,周期性反復發(fā)生。下面可以查看綁定變量捕獲的信息。



select * from v$sql twhere t.sql_text like '%from t1%'

SELECT t4.NAME,

????? ?t4.POSITION,

?????? t4.VALUE_STRING,

?????? t4.WAS_CAPTURED,

?????? t4.LAST_CAPTURED

FROM?? V$sql_bind_capture t4

WHERE? sql_id = '0cb0dywxmcpwf';


NAME? POSITION VALUE WAS_C LAST_CAPTU

----- -------- ---------- ----------

:B1? 1??? 1??? YES? 2018/5/916:28:06


五、案列2:綁定變量類型問題


首先,為了證明這個測試不是因為上面的綁定變量窺視而引起的不一致,所以把綁定變量窺視功能關掉了。



SQL> alter sessionset "_optim_peek_user_binds" = false;


會話已更改。



對C2列使用綁定變量,進行觀察。從下面可以看到,預估執(zhí)行計劃里使用了索引。



SQL> var b2number;

SQL> exec :b2 :=1;


PL/SQL 過程已成功完成。


SQL> explain planfor

? ??select count(c2)

??? from t1

??? where c2 = :b2;


已解釋。


SQL> select * fromtable(dbms_xplan.display(null,null,'typical'));


-------------------------------------------------------------------------------

| Id? | Operation???????? | Name????? | Rows?| Bytes | Cost (%CPU)| Time???? |

-------------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT? |??????????|???? 1 |???? 4 |????1?? (0)| 00:00:01 |

|?? 1 |?SORT AGGREGATE?? |?????????? |????1 |???? 4 |?????????? ?|?????????|

|*? 2 |??INDEX RANGE SCAN| IDX_T1_C2 |????2 |???? 8 |???? 1??(0)| 00:00:01 |

-------------------------------------------------------------------------------


Predicate Information(identified by operation id):

---------------------------------------------------


?? 2 - access("C2"=:B2)



ExplainPlan命令只會查看是否存在綁定變量,而不會考慮綁定變量的類型是什么,其值是什么,始終會把綁定變量的類型設為VARCHAR2類型進行考慮。所以,上面的例子里不管對綁定變量B2如何定義,ExplainPlan里預估執(zhí)行計劃始終是一樣。

但是,真實執(zhí)行計劃里沒有選擇INDEX RANGE SCAN,而是選擇了 TABLE FULL SCAN。



SQL> select /*+gather_plan_statistics */ count(c2)

?? from t1

??? where c2 = :b2;


?COUNT(C2)

----------

???? 10001


SQL> select * fromtable(dbms_xplan.display_cursor(null,null,'allstats last'));



-------------------------------------------------------------------------------------

| Id? | Operation????????? | Name | Starts | E-Rows | A-Rows|?? A-Time?? | Buffers |

-------------------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT?? |?????|????? 1 |??????? |?????1 |00:00:00.01 |???? ?39 |

|?? 1 |?SORT AGGREGATE??? |????? |?????1 |????? 1 |????? 1 |00:00:00.01 |????? 39 |

|*? 2 |??TABLE ACCESS FULL| T1?? |????? 1 |?????2 |? 10001 |00:00:00.01 |????? 39 |

-------------------------------------------------------------------------------------


Predicate Information(identified by operation id):

---------------------------------------------------


?? 2 - filter(TO_NUMBER("C2")=:B2)



為什么會發(fā)生這種情況?綁定變量窺視功能已經(jīng)關閉了,所以肯定不是綁定變量窺視的問題。這里需要注意的是,C2列是VARCHAR2類型,綁定變量B2是NUMBER類型。這時,Oracle會進行隱式轉換,VARCHAR2類型會被轉換成NUMBER類型,即,NUMBER類型的優(yōu)先級更高。所以,會對C2列進行隱式轉換(VARCHAR2 →NUMBER),從而不能使用C2列的索引。可以在謂詞信息(Predicate Information)中確認。



Predicate Information(identified by operation id):

---------------------------------------------------


?? 2 - filter(TO_NUMBER("C2")=:B2)



為了再次證明這個是因為隱式轉換的問題,我們使用VARCHAR2類型的綁定變量B3進行測試。



SQL> var b3varchar2(10);

SQL> exec :b3 :='1';


PL/SQL 過程已成功完成。


SQL> select /*+gather_plan_statistics */ count(c2)

??? from t1

??? where c2 = :b3;


?COUNT(C2)

----------

???? 10001


SQL> select * fromtable(dbms_xplan.display_cursor(null,null,'allstats last'));



-----------------------------------------------------------------------------------------

| Id? | Operation???????? | Name????? | Starts | E-Rows | A-Rows |?? A-Time??| Buffers |

-----------------------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT? |??????????|????? 1 |??????? |?????1 |00:00:00.01 |????? 20 |

|?? 1 |?SORT AGGREGATE?? |?????????? |????? 1 |?????1 |????? 1 |00:00:00.01 |????? 20 |

|*? 2 |??INDEX RANGE SCAN| IDX_T1_C2 |?????1 |????? 2 |? 10001 |00:00:00.01 |????? 20 |

-----------------------------------------------------------------------------------------


Predicate Information(identified by operation id):

---------------------------------------------------


?? 2 - access("C2"=:B3)



從上面可以看到,綁定變量類型是VARCHAR2的時候,沒有進行隱式轉換,產生了與預估執(zhí)行計劃相同的執(zhí)行計劃,使用了索引的范圍掃描。

這個例子也說明,不能完全相信預估的執(zhí)行計劃。內部的一些轉換(比如列的隱式轉換)會使執(zhí)行計劃改變,甚至有時候會出現(xiàn)不希望的執(zhí)行計劃。



六、案列3:統(tǒng)計信息收集的參數(shù)問題


下面SQL的預估執(zhí)行計劃與實際執(zhí)行計劃完全一致。



SQL> explain planfor

??? select count(c2)

??? from t1

??? where c1 = 2;


已解釋。

select * fromtable(dbms_xplan.display(null,null,'typical'));


------------------------------------------------------------------------------------------

| Id? | Operation??????????????????? | Name????? | Rows?| Bytes | Cost (%CPU)| Time???? |

------------------------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT???????????? |?????????? |????1 |???? 6 |???? 2??(0)| 00:00:01 |

|?? 1 |?SORT AGGREGATE????????????? |?????????? |????1 |???? 6 |??????????? |?????????|

|?? 2 |??TABLE ACCESS BY INDEX ROWID| T1???????|???? 1 |???? 6 |????2?? (0)| 00:00:01 |

|*? 3 |???INDEX RANGE SCAN????????? |IDX_T1_C1 |???? 1 |?????? |????1?? (0)| 00:00:01 |

------------------------------------------------------------------------------------------


Predicate Information(identified by operation id):

---------------------------------------------------


?? 3 - access("C1"=2)



SQL> select? /*+ gather_plan_statistics */ count(c2)

??? from t1

??? where c1 = 2;


?COUNT(C2)

----------

???????? 1


SQL> select * fromtable(dbms_xplan.display_cursor(null,null,'allstats last'));


----------------------------------------------------------------------------------------------------

| Id? | Operation??????????????????? | Name????? | Starts | E-Rows | A-Rows |?? A-Time??| Buffers |

----------------------------------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT???????????? |?????????? |????? 1 |???????|????? 1 |00:00:00.01 |?????? 3 |

|?? 1 |? SORTAGGREGATE????????????? |?????????? |????? 1 |?????1 |????? 1 |00:00:00.01 |?????? 3 |

|?? 2 |??TABLE ACCESS BY INDEX ROWID| T1???????|????? 1 |????? 1 |?????1 |00:00:00.01 |?????? 3 |

|*? 3 |???INDEX RANGE SCAN????????? |IDX_T1_C1 |????? 1 |??? ??1|????? 1 |00:00:00.01 |?????? 2 |

----------------------------------------------------------------------------------------------------


Predicate Information(identified by operation id):

---------------------------------------------------


?? 3 - access("C1"=2)



對T1表的 C1 = 2,C2=1的值增加20,000個,之后重新收集統(tǒng)計信息,但是NO_INVALIDATE參數(shù)設為NULL,NULL的意思是讓Oracle自動處理的意思。NO_INVALIDATE其他參數(shù)情況參考如下:


[if !supportLists]l? [endif]NO_INVALIDATE=TRUE更新統(tǒng)計信息,但對有從屬(Dependency)關系的SQL 不進行Invalidation。為了避免一次性大量的硬解析(Hard Parse)現(xiàn)象的發(fā)生。SQL如果在SGA里Age Out后,再次執(zhí)行的時候,才會用到更新后的統(tǒng)計信息。

[if !supportLists]l? [endif]NO_INVALIDATE=FALSE:更新統(tǒng)計信息,并對有從屬(Dependency)關系的SQL 馬上進行Invalidation。

[if !supportLists]l? [endif]NO_INVALIDATE=AUTO(NULL)更新統(tǒng)計信息,但對有從屬關系的SQL不會一次性的進行Invalidation,而是在最大5小時(18,000秒)內隨機進行Invalidation的方式進行??梢哉f是TRUE與FALSE的中間形式。18,000秒是可以通過_OPTIMIZER_INVALIDATION_PERIOD參數(shù)進行設定。


現(xiàn)在對表T1增加數(shù)據(jù),并收集統(tǒng)計信息,但是NO_INVALIDATE參數(shù)設為NULL(默認值是NULL)。



SQL> insert intot1 select 2,'1' from dual connect by level <= 20000;


已創(chuàng)建20000行。


SQL> execdbms_stats.gather_table_stats(user,'T1',method_opt => 'for all columns size5',no_invalidate => null);


PL/SQL 過程已成功完成。



Explain Plan命令始終是在用最新的統(tǒng)計信息,所以從下面可以看到,ExplainPlan命令對C1=2的條件使用了最新的統(tǒng)計信息,執(zhí)行計劃選擇了Table Full Scan。預估行數(shù)為16,000行,與實際行數(shù)20,001行數(shù)相當接近。因為存在列的直方圖,這種預估是可行的。



SQL> explain planfor

??? select count(t1.c2)

??? from sys.t1

??? where t1.c1 = 2 ;


已解釋。


SQL> select * fromtable(dbms_xplan.display());



---------------------------------------------------------------------------

| Id? | Operation????????? | Name | Rows? | Bytes | Cost (%CPU)| Time???? |

---------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT?? |?????|???? 1 |???? 6 |???20?? (0)| 00:00:01 |

|?? 1 |?SORT AGGREGATE??? |????? |????1 |???? 6 |??????????? |????????? |

|*? 2 |??TABLE ACCESS FULL| T1?? | 16000 |96000 |??? 20?? (0)| 00:00:01 |

---------------------------------------------------------------------------


Predicate Information(identified by operation id):

---------------------------------------------------


?? 2 - filter("T1"."C1"=2)



但是,在真實執(zhí)行計劃中仍然選擇了Index Range Scan,因為雖然統(tǒng)計信息更新了,但是相關的SQL還沒有被Invalidation。



SQL> select? /*+ gather_plan_statistics */ count(c2)

??? from t1

??? where c1 = 2;


?COUNT(C2)

----------

???? 20001


SQL> select * fromtable(dbms_xplan.display_cursor(null,null,'allstats last'));



----------------------------------------------------------------------------------------------------

| Id? | Operation??????????????????? ??| Name?????| Starts | E-Rows | A-Rows |??A-Time?? | Buffers |

----------------------------------------------------------------------------------------------------

|?? 0 | SELECT STATEMENT???????????? ??|??????????|????? 1 |??????? |?????1 |00:00:00.02 |???? 102 |

|?? 1 |?SORT AGGREGATE????????????? ??|??????????|????? 1 |????? 1 |?????1 |00:00:00.02 |???? 102 |

|?? 2 |??TABLE ACCESS BY INDEX ROWID | T1???????|?????1 |????? 2 |? 20001 |00:00:00.02 |???? 102 |

|*? 3 |???INDEX RANGE SCAN????????? ??| IDX_T1_C1 |????? 1 |?????2 |? 20001 |00:00:00.01 |????? 70 |

----------------------------------------------------------------------------------------------------


Predicate Information(identified by operation id):

---------------------------------------------------


?? 3 - access("C1"=2)



如果只看Explain Plan后就判斷“執(zhí)行計劃的效率不錯”是不可取的,會根據(jù)不同的情況產生很大的性能差異。這時可以通過DBMS_SHARED_POOL.PURGE存儲過程,或使用清理共享池(Shared Pool Flush)等方法強制反應最新的統(tǒng)計信息。


七、總結


預估執(zhí)行計劃與真實執(zhí)行計劃產生差異的原因,其實是多種多樣的,在分析其原因的過程中發(fā)現(xiàn)需要相當多的知識點。

產生差異的原因,其中最普遍的有因綁定變量的窺視,也有因綁定變量的隱式轉換,也有因參數(shù)差異,也有因統(tǒng)計信息收集參數(shù)等問題。

不能對預估執(zhí)行計劃100%信任,一定要實際執(zhí)行以后驗證其結果。如果這個過程中想解釋執(zhí)行計劃異常的現(xiàn)象,需要了解DBMS_XPLAN包的使用方法與對其結果的正確理解。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容