為什么 ExplainPlan 與RuntimePlan 會(huì)有差異

為什么預(yù)估執(zhí)行計(jì)劃與真實(shí)執(zhí)行計(jì)劃會(huì)有差異?




一、問題概要


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


二澈歉、問題解答


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

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


[if !supportLists]l? [endif]綁定變量窺視(Bind Peeking:Explain Plan里不會(huì)進(jìn)行綁定變量窺視凯砍,但是Runtime Plan里會(huì)進(jìn)行綁定變量窺視,所以拴竹,如果這種情況發(fā)生會(huì)使兩個(gè)執(zhí)行計(jì)劃會(huì)產(chǎn)生差異悟衩。

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

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

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


?? ?預(yù)估執(zhí)行計(jì)劃與實(shí)際執(zhí)行計(jì)劃產(chǎn)生差異的原因總結(jié)為上面幾種情況,當(dāng)然也有因Oracle Bug的原因也會(huì)有產(chǎn)生執(zhí)行計(jì)劃的差異情況中狂。

下面通過幾個(gè)測(cè)試凫碌,加深對(duì)上面的問題的理解。


三胃榕、測(cè)試環(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表有如下特點(diǎn):

表名列名列類型說明

T1C1Number“1”值有10,000個(gè)勋又,“1~10000”的值各一個(gè)苦掘,總共有10,000種值

C2Varchar2同上

之后,對(duì)列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)建端铛。


對(duì)表T1進(jìn)行統(tǒng)計(jì)信息收集泣矛。METHOD_OPT 的參數(shù)設(shè)為 ALL

COLUMNS SIZE 5 ,即禾蚕,直方圖的BUCKETS個(gè)數(shù)指定為5您朽。但是列C1和C2有 10,000個(gè)不同的值,BUCKETS個(gè)數(shù)為5的話换淆,會(huì)生成等高直方圖(HEIGHT BALANCED)哗总。


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


PL/SQL 過程已成功完成。



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


--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

下面我們看下讯屈,因綁定變量窺視,而引起的預(yù)估執(zhí)行計(jì)劃與實(shí)際執(zhí)行計(jì)劃不一致的情況县习。首先涮母,激活綁定變量窺視功能,默認(rèn)值就是TRUE躁愿。



SQL> alter sessionset "_optim_peek_user_binds" = true;


會(huì)話已更改叛本。



首先,我們輸出預(yù)估執(zhí)行計(jì)劃彤钟。從下面可以看到来候,執(zhí)行計(jì)劃選擇的是索引范圍掃描(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的實(shí)際值是“1”。T1表里值為1的記錄數(shù)將近占50%峡眶,這種情況與其選擇索引范圍掃剧防,不如選擇全表掃(Table Full Scan)會(huì)有效率一些。但是 ExplainPlan命令不進(jìn)行綁定變量的窺視辫樱,即峭拘,在創(chuàng)建預(yù)估執(zhí)行計(jì)劃的過程中砂代,會(huì)把綁定變量的值設(shè)為未知(Uknown)來處理喘垂,不會(huì)考慮實(shí)際的綁定變量的值到底是什么。所以懈贺,ExplainPlan不關(guān)心其值是不是“1”搬男,而只考慮Distinct Count來建立執(zhí)行計(jì)劃拣展。

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


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


但是备埃,實(shí)際執(zhí)行計(jì)劃與上面的結(jié)果完全不一樣姓惑,如下。



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í)行計(jì)劃前讀取了綁定變量的實(shí)際的值(進(jìn)行是窺視)辅搬。之后唯沮,參考綁定變量的值來創(chuàng)建執(zhí)行計(jì)劃。這個(gè)例子堪遂,使用了值“1”來創(chuàng)建了執(zhí)行計(jì)劃介蛉。所以,預(yù)估行數(shù)從ExplainPlan里的2 變成了8000溶褪。其原因如下:

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

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

實(shí)際行數(shù)為10,001,預(yù)估值與實(shí)際值相當(dāng)接近了币旧。

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



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)是對(duì)特定SQL里使用的綁定變量值按照固定周期放到SGA里保存的情況于游。最初的綁定變量窺視與綁定變量捕獲的時(shí)間是一樣毁葱,約15分鐘(900秒)后,綁定變量捕獲會(huì)再次發(fā)生贰剥,周期性反復(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:綁定變量類型問題


首先前痘,為了證明這個(gè)測(cè)試不是因?yàn)樯厦娴慕壎ㄗ兞扛Q視而引起的不一致,所以把綁定變量窺視功能關(guān)掉了担忧。



SQL> alter sessionset "_optim_peek_user_binds" = false;


會(huì)話已更改芹缔。



對(duì)C2列使用綁定變量,進(jìn)行觀察瓶盛。從下面可以看到最欠,預(yù)估執(zhí)行計(jì)劃里使用了索引。



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命令只會(huì)查看是否存在綁定變量,而不會(huì)考慮綁定變量的類型是什么轧房,其值是什么拌阴,始終會(huì)把綁定變量的類型設(shè)為VARCHAR2類型進(jìn)行考慮。所以奶镶,上面的例子里不管對(duì)綁定變量B2如何定義迟赃,ExplainPlan里預(yù)估執(zhí)行計(jì)劃始終是一樣陪拘。

但是,真實(shí)執(zhí)行計(jì)劃里沒有選擇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)



為什么會(huì)發(fā)生這種情況?綁定變量窺視功能已經(jīng)關(guān)閉了摄乒,所以肯定不是綁定變量窺視的問題。這里需要注意的是残黑,C2列是VARCHAR2類型馍佑,綁定變量B2是NUMBER類型。這時(shí)梨水,Oracle會(huì)進(jìn)行隱式轉(zhuǎn)換拭荤,VARCHAR2類型會(huì)被轉(zhuǎn)換成NUMBER類型,即疫诽,NUMBER類型的優(yōu)先級(jí)更高舅世。所以,會(huì)對(duì)C2列進(jìn)行隱式轉(zhuǎn)換(VARCHAR2 →NUMBER)奇徒,從而不能使用C2列的索引雏亚。可以在謂詞信息(Predicate Information)中確認(rèn)摩钙。



Predicate Information(identified by operation id):

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


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



為了再次證明這個(gè)是因?yàn)殡[式轉(zhuǎn)換的問題罢低,我們使用VARCHAR2類型的綁定變量B3進(jìn)行測(cè)試。



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的時(shí)候,沒有進(jìn)行隱式轉(zhuǎn)換长踊,產(chǎn)生了與預(yù)估執(zhí)行計(jì)劃相同的執(zhí)行計(jì)劃功舀,使用了索引的范圍掃描。

這個(gè)例子也說明身弊,不能完全相信預(yù)估的執(zhí)行計(jì)劃辟汰。內(nèi)部的一些轉(zhuǎn)換(比如列的隱式轉(zhuǎn)換)會(huì)使執(zhí)行計(jì)劃改變,甚至有時(shí)候會(huì)出現(xiàn)不希望的執(zhí)行計(jì)劃阱佛。



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


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



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)



對(duì)T1表的 C1 = 2涨冀,C2=1的值增加20,000個(gè),之后重新收集統(tǒng)計(jì)信息麦萤,但是NO_INVALIDATE參數(shù)設(shè)為NULL鹿鳖,NULL的意思是讓Oracle自動(dòng)處理的意思扁眯。NO_INVALIDATE其他參數(shù)情況參考如下:


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

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

[if !supportLists]l? [endif]NO_INVALIDATE=AUTO(NULL)更新統(tǒng)計(jì)信息杂抽,但對(duì)有從屬關(guān)系的SQL不會(huì)一次性的進(jìn)行Invalidation,而是在最大5小時(shí)(18,000秒)內(nèi)隨機(jī)進(jìn)行Invalidation的方式進(jìn)行韩脏∷豸铮可以說是TRUE與FALSE的中間形式。18,000秒是可以通過_OPTIMIZER_INVALIDATION_PERIOD參數(shù)進(jìn)行設(shè)定赡矢。


現(xiàn)在對(duì)表T1增加數(shù)據(jù)杭朱,并收集統(tǒng)計(jì)信息,但是NO_INVALIDATE參數(shù)設(shè)為NULL(默認(rèn)值是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)計(jì)信息空民,所以從下面可以看到梦谜,ExplainPlan命令對(duì)C1=2的條件使用了最新的統(tǒng)計(jì)信息,執(zhí)行計(jì)劃選擇了Table Full Scan袭景。預(yù)估行數(shù)為16,000行唁桩,與實(shí)際行數(shù)20,001行數(shù)相當(dāng)接近。因?yàn)榇嬖诹械闹狈綀D耸棒,這種預(yù)估是可行的荒澡。



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)



但是与殃,在真實(shí)執(zhí)行計(jì)劃中仍然選擇了Index Range Scan单山,因?yàn)殡m然統(tǒng)計(jì)信息更新了,但是相關(guān)的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ì)劃的效率不錯(cuò)”是不可取的米奸,會(huì)根據(jù)不同的情況產(chǎn)生很大的性能差異。這時(shí)可以通過DBMS_SHARED_POOL.PURGE存儲(chǔ)過程爽篷,或使用清理共享池(Shared Pool Flush)等方法強(qiáng)制反應(yīng)最新的統(tǒng)計(jì)信息悴晰。


七、總結(jié)


預(yù)估執(zhí)行計(jì)劃與真實(shí)執(zhí)行計(jì)劃產(chǎn)生差異的原因,其實(shí)是多種多樣的铡溪,在分析其原因的過程中發(fā)現(xiàn)需要相當(dāng)多的知識(shí)點(diǎn)漂辐。

產(chǎn)生差異的原因,其中最普遍的有因綁定變量的窺視棕硫,也有因綁定變量的隱式轉(zhuǎn)換髓涯,也有因參數(shù)差異,也有因統(tǒng)計(jì)信息收集參數(shù)等問題哈扮。

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赦邻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌实檀,老刑警劉巖惶洲,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異膳犹,居然都是意外死亡恬吕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門须床,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铐料,“玉大人,你說我怎么就攤上這事豺旬∧瞥停” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵族阅,是天一觀的道長(zhǎng)篓跛。 經(jīng)常有香客問我,道長(zhǎng)坦刀,這世上最難降的妖魔是什么愧沟? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮鲤遥,結(jié)果婚禮上沐寺,老公的妹妹穿的比我還像新娘。我一直安慰自己盖奈,他們只是感情好混坞,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钢坦,像睡著了一般拔第。 火紅的嫁衣襯著肌膚如雪咕村。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天蚊俺,我揣著相機(jī)與錄音懈涛,去河邊找鬼。 笑死泳猬,一個(gè)胖子當(dāng)著我的面吹牛批钠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播得封,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼埋心,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了忙上?” 一聲冷哼從身側(cè)響起拷呆,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎疫粥,沒想到半個(gè)月后茬斧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡梗逮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年项秉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慷彤。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡娄蔼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出底哗,到底是詐尸還是另有隱情岁诉,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布跋选,位于F島的核電站唉侄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏野建。R本人自食惡果不足惜属划,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望候生。 院中可真熱鬧同眯,春花似錦、人聲如沸唯鸭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至明肮,卻和暖如春菱农,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柿估。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工循未, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秫舌。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓的妖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親足陨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嫂粟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 1.數(shù)據(jù)庫三范式是什么? 第一范式:表中每個(gè)字段都不能再分。 第二范式:滿足第一范式并且表中的非主鍵字段都依賴于主...
    杰倫哎呦哎呦閱讀 2,854評(píng)論 0 28
  • 備注:測(cè)試數(shù)據(jù)庫版本為MySQL 8.0 一.使用EXPLAIN優(yōu)化查詢 1.1 Explain語法及概述 語法:...
    只是甲閱讀 530評(píng)論 0 0
  • 一墨缘、新特性 Mysql和Innodb增強(qiáng): 1星虹、undo可以新增表空間mysql> CREATE UNDO TAB...
    重慶八怪閱讀 1,348評(píng)論 0 0
  • MySQL全面優(yōu)化1.優(yōu)化哲學(xué)1.1 為什么優(yōu)化?為了獲得成就感?為了證實(shí)比系統(tǒng)設(shè)計(jì)者更懂?dāng)?shù)據(jù)庫?為了從優(yōu)化成果來...
    5不忘初心0閱讀 340評(píng)論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月镊讼,有人笑有人哭宽涌,有人歡樂有人憂愁,有人驚喜有人失落狠毯,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,523評(píng)論 28 53