Oracle優化器之基數反饋(CardinalityFeedback)功能

概述

Oracle 11gR2的版本上推出了基數反饋(Cardinality Feedback 之後簡稱CFB)功能,經過這個特性,對於某些查詢在第一次執行時,若是CBO發現根據統計信息估算出的基數(Computed cardinality)和SQL執行時的實際值差距很大的狀況發生時,在SQL下次執行時,會根據實際值調整基數,從新生成執行計劃。ios

另外,基數反饋 (CFB)在12c版本上獲得更進一步的擴展改稱爲統計反饋(Statistics Feedback),成爲12c自動從新優化(Automatic Reoptimization)的一部分。
關於這統計反饋(Statistics Feedback)中擴展的內容和12c自動從新優化(Automatic Reoptimization)的內容,將在之後的章節中進行介紹。sql

下面咱們將經過幾個例子來了解一下CFB功能。數據庫

例子1(CFB無效)

首先咱們在10.2.0.5的環境中也就是CFB無效的狀況下,看看執行的狀況:
(咱們使用了Oracle數據庫提供的樣例Schema OE 及其表PRODUCT_INFORMATION和ORDER_ITEMS進行測試。)session

1.首先確認相關表的統計信息和表的數據量。(基於10.2.0.5版本測試)ide

--統計信息可以反映出表中的數據量。
SQL> select TABLE_NAME,NUM_ROWS,BLOCKS from user_tables where TABLE_NAME in ('PRODUCT_INFORMATION','ORDER_ITEMS');
 
TABLE_NAME             NUM_ROWS     BLOCKS 
-------------------- ---------- ---------- 
ORDER_ITEMS                 665          5 
PRODUCT_INFORMATION         288         13 
 
SQL> select count(*) from ORDER_ITEMS;
 
  COUNT(*)
----------
       665
 
SQL> select count(*) from PRODUCT_INFORMATION;
 
  COUNT(*)
----------
       288

2.設定環境參數statistics_level爲ALL,以便可以經過dbms_xplan.display_cursor函數查看SQL文根據統計信息估算出的訪問數據行數和SQL執行時的實際值。函數

SQL> alter session set statistics_level=all;
 
Session altered.

3.第一次執行SQL測試

SQL> SELECT  o.order_id, v.product_name
  2  FROM   orders o,
  3         ( SELECT order_id, product_name
  4           FROM   order_items o, product_information p
  5           WHERE  p.product_id = o.product_id
  6           AND    list_price < 50
  7           AND    min_price < 40 ) v
  8  WHERE  o.order_id = v.order_id
  9  ;
 
  ORDER_ID PRODUCT_NAME        
---------- --------------------
      2354 Sound Card STD      
...
      2457 Graphics - DIK+     
 
269 rows selected.

4.查看第一次執行後的執行計劃優化

SQL> select * from table(dbms_xplan.display_cursor(NULL, NULL,'typical iostats last -cost -bytes'));
 
PLAN_TABLE_OUTPUT              
------------------------------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 0
-------------------------------------
SELECT  o.order_id, v.product_name FROM   orders o,        ( SELECT order_id, product_name          FROM         
order_items o, product_information p          WHERE  p.product_id = o.product_id          AND    list_price < 50  
       AND    min_price < 40 ) v WHERE  o.order_id = v.order_id  
 
Plan hash value: 1906736282    
 
---------------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name                | Starts | E-Rows | E-Time   | A-Rows |   A-Time   | Buffers | Reads  |
---------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                     |      1 |        |          |    269 |00:00:00.44 |    9189 |     20 |
|   1 |  NESTED LOOPS         |                     |      1 |      1 | 00:00:01 |    269 |00:00:00.44 |    9189 |     20 |
|   2 |   MERGE JOIN CARTESIAN|                     |      1 |      4 | 00:00:01 |   9135 |00:00:00.17 |      35 |     15 |
|*  3 |    TABLE ACCESS FULL  | PRODUCT_INFORMATION |      1 |      1 ★| 00:00:01 |     87 ★|00:00:00.01 |      34 |     14 |
|   4 |    BUFFER SORT        |                     |     87 |    105 | 00:00:01 |   9135 |00:00:00.07 |       1 |      1 |
|   5 |     INDEX FULL SCAN   | ORDER_PK            |      1 |    105 | 00:00:01 |    105 |00:00:00.01 |       1 |      1 |
|*  6 |   INDEX UNIQUE SCAN   | ORDER_ITEMS_UK      |   9135 |      1 |          |    269 |00:00:00.18 |    9154 |      5 |
---------------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):              
---------------------------------------------------              
 
   3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))              
   6 - access("O"."ORDER_ID"="ORDER_ID" AND "P"."PRODUCT_ID"="O"."PRODUCT_ID")        
 
 
26 rows selected.
 
SQL> ---查看V$SQL的統計信息。
SQL> select sql_id,child_number, executions, buffer_gets,plan_hash_value
  2  from v$sql
  3  where sql_id = 'bmh5hb8331u33';
 
SQL_ID        CHILD_NUMBER EXECUTIONS BUFFER_GETS PLAN_HASH_VALUE
------------- ------------ ---------- ----------- ---------------
bmh5hb8331u33            0          1        9701      1906736282

咱們發現因爲訪問條件(「MIN_PRICE」<40 AND 「LIST_PRICE」<50)的影響,優化器認爲PRODUCT_INFORMATION表的預估行數(E-Rows)爲1,優化器基於預估基數在選擇表PRODUCT_INFORMATION和ORDER_ITEMS結合的最優執行計劃時,選擇了MERGE JOIN CARTESIAN的結合方式。
但實際實際訪問行數(A-Time:87),所以因爲預估基數不許,頗有可能致使選擇的執行計劃不是最優的。this

5.咱們再屢次執行相同的SQL文spa

---第二次執行
SQL> SELECT  o.order_id, v.product_name
  2  FROM   orders o,
  3         ( SELECT order_id, product_name
  4           FROM   order_items o, product_information p
  5           WHERE  p.product_id = o.product_id
  6           AND    list_price < 50
  7           AND    min_price < 40 ) v
  8  WHERE  o.order_id = v.order_id
  9  ;
 
  ORDER_ID PRODUCT_NAME        
---------- --------------------
      2354 Sound Card STD      
...
      2457 Graphics - DIK+     
 
269 rows selected.
 
SQL> 
---第二次執行的執行計劃
SQL> select * from table(dbms_xplan.display_cursor(NULL, NULL,'typical iostats last -cost -bytes'));
 
PLAN_TABLE_OUTPUT              
------------------------------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 0
-------------------------------------
SELECT  o.order_id, v.product_name FROM   orders o,        ( SELECT order_id, product_name          FROM         
 order_items o, product_information p          WHERE  p.product_id = o.product_id          AND                   
list_price < 50          AND    min_price < 40 ) v WHERE  o.order_id = v.order_id     
 
Plan hash value: 1906736282    
 
------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name                | Starts | E-Rows | E-Time   | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                     |      1 |        |          |    269 |00:00:00.45 |    9189 |
|   1 |  NESTED LOOPS         |                     |      1 |      1 | 00:00:01 |    269 |00:00:00.45 |    9189 |
|   2 |   MERGE JOIN CARTESIAN|                     |      1 |      4 | 00:00:01 |   9135 |00:00:00.17 |      35 |
|*  3 |    TABLE ACCESS FULL  | PRODUCT_INFORMATION |      1 |      1 | 00:00:01 |     87 |00:00:00.01 |      34 |
|   4 |    BUFFER SORT        |                     |     87 |    105 | 00:00:01 |   9135 |00:00:00.06 |       1 |
|   5 |     INDEX FULL SCAN   | ORDER_PK            |      1 |    105 | 00:00:01 |    105 |00:00:00.01 |       1 |
|*  6 |   INDEX UNIQUE SCAN   | ORDER_ITEMS_UK      |   9135 |      1 |          |    269 |00:00:00.18 |    9154 |
------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):              
---------------------------------------------------              
 
   3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))              
   6 - access("O"."ORDER_ID"="ORDER_ID" AND "P"."PRODUCT_ID"="O"."PRODUCT_ID")        
 
 
26 rows selected.
 
---第三次執行的執行計劃
 
    SQL> SELECT  o.order_id, v.product_name
  2  FROM   orders o,
  3         ( SELECT order_id, product_name
  4           FROM   order_items o, product_information p
  5           WHERE  p.product_id = o.product_id
  6           AND    list_price < 50
  7           AND    min_price < 40 ) v
  8  WHERE  o.order_id = v.order_id
  9  ;
 
  ORDER_ID PRODUCT_NAME        
---------- --------------------
      2354 Sound Card STD      
...
      2457 Graphics - DIK+     
 
269 rows selected.
 
--第三次執行的執行計劃    
SQL> select * from table(dbms_xplan.display_cursor(NULL, NULL,'typical iostats last -cost -bytes'));
 
PLAN_TABLE_OUTPUT              
------------------------------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 0
-------------------------------------
SELECT  o.order_id, v.product_name FROM   orders o,        ( SELECT order_id, product_name          FROM         
 order_items o, product_information p          WHERE  p.product_id = o.product_id          AND                   
list_price < 50          AND    min_price < 40 ) v WHERE  o.order_id = v.order_id     
 
Plan hash value: 1906736282    
 
------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name                | Starts | E-Rows | E-Time   | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                     |      1 |        |          |    269 |00:00:00.45 |    9189 |
|   1 |  NESTED LOOPS         |                     |      1 |      1 | 00:00:01 |    269 |00:00:00.45 |    9189 |
|   2 |   MERGE JOIN CARTESIAN|                     |      1 |      4 | 00:00:01 |   9135 |00:00:00.16 |      35 |
|*  3 |    TABLE ACCESS FULL  | PRODUCT_INFORMATION |      1 |      1 | 00:00:01 |     87 |00:00:00.01 |      34 |
|   4 |    BUFFER SORT        |                     |     87 |    105 | 00:00:01 |   9135 |00:00:00.07 |       1 |
|   5 |     INDEX FULL SCAN   | ORDER_PK            |      1 |    105 | 00:00:01 |    105 |00:00:00.01 |       1 |
|*  6 |   INDEX UNIQUE SCAN   | ORDER_ITEMS_UK      |   9135 |      1 |          |    269 |00:00:00.19 |    9154 |
------------------------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):              
---------------------------------------------------              
 
   3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))              
   6 - access("O"."ORDER_ID"="ORDER_ID" AND "P"."PRODUCT_ID"="O"."PRODUCT_ID")        
 
 
26 rows selected.

咱們發現,雖然根據統計信息估算出的基數(Computed cardinality)和SQL執行時的實際值不一樣,可是之後的執行過程當中,SQL文依然會利用之前的執行計劃(軟解析)。
在這個狀況下,頗有可能因爲最初優化器沒有選擇最優的執行計劃,在之後的重複執行中也得不到改進而致使效率問題。

例子2(CFB有效)

下面咱們在11.2.0.4的環境中也就是CFB有效的狀況下,看看執行的狀況:
(咱們依然使用Oracle數據庫提供的樣例Schema OE 及其表PRODUCT_INFORMATION和ORDER_ITEMS進行測試。)

1.首先確認相關表的統計信息和表的數據量。(基於11.2.0.4版本測試)

--統計信息可以反映出表中的數據量。
    SQL> select TABLE_NAME,NUM_ROWS,BLOCKS from user_tables where TABLE_NAME in ('PRODUCT_INFORMATION','ORDER_ITEMS');
 
TABLE_NAME             NUM_ROWS     BLOCKS 
-------------------- ---------- ---------- 
ORDER_ITEMS                 665          5 
PRODUCT_INFORMATION         288         13 
 
Elapsed: 00:00:00.04
SQL> select count(*) from ORDER_ITEMS;
 
  COUNT(*)
----------
       665
 
Elapsed: 00:00:00.02
SQL> select count(*) from PRODUCT_INFORMATION;
 
  COUNT(*)
----------
       288
 
Elapsed: 00:00:00.01
SQL>

2.設定環境參數statistics_level爲ALL,以便可以經過dbms_xplan.display_cursor函數查看SQL文根據統計信息估算出的訪問數據行數和SQL執行時的實際值。

SQL> alter session set statistics_level=all;
 
Session altered.
 
Elapsed: 00:00:00.01

3.第一次執行SQL

SQL> 
SQL> SELECT  o.order_id, v.product_name
  2  FROM   orders o,
  3         ( SELECT order_id, product_name
  4           FROM   order_items o, product_information p
  5           WHERE  p.product_id = o.product_id
  6           AND    list_price < 50
  7           AND    min_price < 40 ) v
  8  WHERE  o.order_id = v.order_id
  9  ;
 
  ORDER_ID PRODUCT_NAME                                     
---------- --------------------                             
      2403 Battery - EL                                     
...
      2450 Plastic Stock - W/HD                             
 
269 rows selected.
 
Elapsed: 00:00:00.22
SQL>

4.查看第一次執行後的執行計劃

SQL> select * from table(dbms_xplan.display_cursor(format=>'typical iostats last -cost -bytes'));
 
PLAN_TABLE_OUTPUT                                           
---------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 0                       
-------------------------------------                       
SELECT  o.order_id, v.product_name FROM   orders o,        ( SELECT                                                              
order_id, product_name          FROM   order_items o,       
product_information p          WHERE  p.product_id = o.product_id                                                                 
   AND    list_price < 50          AND    min_price < 40 ) v WHERE                                                               
o.order_id = v.order_id                                     
 
Plan hash value: 1906736282                                 
 
---------------------------------------------------------------------------------------------------------------------------       
| Id  | Operation             | Name                | Starts | E-Rows | E-Time   | A-Rows |   A-Time   | Buffers | Reads  |       
---------------------------------------------------------------------------------------------------------------------------       
|   0 | SELECT STATEMENT      |                     |      1 |        |          |    269 |00:00:00.17 |    1337 |     20 |       
|   1 |  NESTED LOOPS         |                     |      1 |      1 | 00:00:01 |    269 |00:00:00.17 |    1337 |     20 |       
|   2 |   MERGE JOIN CARTESIAN|                     |      1 |      4 | 00:00:01 |   9135 |00:00:00.06 |      33 |     15 |       
|*  3 |    TABLE ACCESS FULL  | PRODUCT_INFORMATION |      1 |   ★ 1 | 00:00:01 |  ★ 87 |00:00:00.01 |      32 |     14 |       
|   4 |    BUFFER SORT        |                     |     87 |    105 | 00:00:01 |   9135 |00:00:00.02 |       1 |      1 |       
|   5 |     INDEX FULL SCAN   | ORDER_PK            |      1 |    105 | 00:00:01 |    105 |00:00:00.01 |       1 |      1 |       
|*  6 |   INDEX UNIQUE SCAN   | ORDER_ITEMS_UK      |   9135 |      1 |          |    269 |00:00:00.05 |    1304 |      5 |       
---------------------------------------------------------------------------------------------------------------------------       
 
Predicate Information (identified by operation id):         
---------------------------------------------------         
 
   3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))         
   6 - access("O"."ORDER_ID"="ORDER_ID" AND "P"."PRODUCT_ID"="O"."PRODUCT_ID")                                                    
 
 
28 rows selected.
 
Elapsed: 00:00:00.19

咱們發現和10.2.0.5環境同樣,因爲訪問條件(「MIN_PRICE」<40 AND 「LIST_PRICE」<50)的影響,優化器認爲PRODUCT_INFORMATION表的預估行數(E-Rows)爲1,優化器基於預估基數在選擇表PRODUCT_INFORMATION和ORDER_ITEMS結合的最優執行計劃時,選擇了MERGE JOIN CARTESIAN的結合方式。

5.查看動態視圖VSQL和VSQL_SHARED_CURSOR

SQL> ---sql_id:bmh5hb8331u33
SQL> select sql_id,child_number, executions, buffer_gets,plan_hash_value
  2  from v$sql
  3  where sql_id = 'bmh5hb8331u33';
 
SQL_ID        CHILD_NUMBER EXECUTIONS BUFFER_GETS PLAN_HASH_VALUE
------------- ------------ ---------- ----------- ---------------
bmh5hb8331u33            0          1        1604      1906736282
 
Elapsed: 00:00:00.01
SQL> 
SQL> select sql_id, child_number, USE_FEEDBACK_STATS
  2  from V$SQL_SHARED_CURSOR
  3  where sql_id = 'bmh5hb8331u33';
 
SQL_ID        CHILD_NUMBER U                                
------------- ------------ -                                
bmh5hb8331u33            0 Y                                
 
Elapsed: 00:00:00.04
SQL>

咱們發現V$SQL_SHARED_CURSOR的USE_FEEDBACK_STATS列標記爲Y。
(USE_FEEDBACK_STATS列是在11.2.0.4 的版本上新追加的列,用於標示當根據統計信息估算出的基數(Computed cardinality)和SQL執行時的實際值差距很大時,下次執行時從新生成執行計劃)

6.咱們再次次執行相同的SQL文

---第二次執行
SQL> SELECT  o.order_id, v.product_name
  2  FROM   orders o,
  3         ( SELECT order_id, product_name
  4           FROM   order_items o, product_information p
  5           WHERE  p.product_id = o.product_id
  6           AND    list_price < 50
  7           AND    min_price < 40 ) v
  8  WHERE  o.order_id = v.order_id
  9  ;
 
  ORDER_ID PRODUCT_NAME                                     
---------- --------------------                             
      2403 Battery - EL                                     
...
      2401 SPNIX3.3 AU                                      
 
269 rows selected.
 
Elapsed: 00:00:00.03★
SQL>

咱們發現執行時間變短了。

7.再次查看執行計劃

SQL> select * from table(dbms_xplan.display_cursor(format=>'typical iostats last -cost -bytes'));
 
PLAN_TABLE_OUTPUT                                           
---------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 1                       
-------------------------------------                       
SELECT  o.order_id, v.product_name FROM   orders o,        ( SELECT
order_id, product_name          FROM   order_items o,       
product_information p          WHERE  p.product_id = o.product_id
   AND    list_price < 50          AND    min_price < 40 ) v WHERE
o.order_id = v.order_id                                     
 
Plan hash value: 35479787                                   
 
----------------------------------------------------------------------------------------------------------------------------      
| Id  | Operation              | Name                | Starts | E-Rows | E-Time   | A-Rows |   A-Time   | Buffers | Reads  |      
----------------------------------------------------------------------------------------------------------------------------      
|   0 | SELECT STATEMENT       |                     |      1 |        |          |    269 |00:00:00.01 |      61 |      1 |      
|   1 |  NESTED LOOPS          |                     |      1 |    313 | 00:00:01 |    269 |00:00:00.01 |      61 |      1 |      
|*  2 |   HASH JOIN            |                     |      1 |    313 | 00:00:01 |    269 |00:00:00.01 |      40 |      1 |      
|*  3 |    TABLE ACCESS FULL   | PRODUCT_INFORMATION |      1 |     ★87 | 00:00:01 |     ★87 |00:00:00.01 |      15 |      0 |      
|   4 |    INDEX FAST FULL SCAN| ORDER_ITEMS_UK      |      1 |    665 | 00:00:01 |    665 |00:00:00.01 |      25 |      1 |      
|*  5 |   INDEX UNIQUE SCAN    | ORDER_PK            |    269 |      1 |          |    269 |00:00:00.01 |      21 |      0 |      
----------------------------------------------------------------------------------------------------------------------------      
 
Predicate Information (identified by operation id):         
---------------------------------------------------         
 
   2 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")            
   3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))         
   5 - access("O"."ORDER_ID"="ORDER_ID")                    
 
Note                                                        
-----                                                       
   - cardinality feedback used for this statement     ★      
 
 
32 rows selected.
 
Elapsed: 00:00:00.03

咱們發現SQL文進行了硬解析,而且表PRODUCT_INFORMATION的預估信息(E-Rows)調整爲第一次執行時收集的實際值(87),用於優化器選擇執行計劃。所以,優化器基於調整後預估基數在選擇表PRODUCT_INFORMATION和ORDER_ITEMS結合的最優執行計劃時,選擇了HASH JOIN的結合方式,從而更有效的執行了SQL文。

8.再次查看動態視圖VSQL和VSQL_SHARED_CURSOR

SQL> ---sql_id:bmh5hb8331u33
SQL> select sql_id,child_number, executions, buffer_gets,plan_hash_value,is_shareable
  2  from v$sql
  3  where sql_id = 'bmh5hb8331u33';
 
SQL_ID        CHILD_NUMBER EXECUTIONS BUFFER_GETS PLAN_HASH_VALUE I
------------- ------------ ---------- ----------- --------------- -
bmh5hb8331u33            0          1        1604      1906736282 N★
bmh5hb8331u33            1          1          61        35479787 Y★
 
Elapsed: 00:00:00.02
SQL> 
SQL> select sql_id, child_number, USE_FEEDBACK_STATS
  2  from V$SQL_SHARED_CURSOR
  3  where sql_id = 'bmh5hb8331u33';
 
SQL_ID        CHILD_NUMBER U
------------- ------------ -
bmh5hb8331u33            0 Y
bmh5hb8331u33            1 N
 
Elapsed: 00:00:00.00

經過視圖V$SQL咱們發現,新生成的遊標CHILD#1比之前的遊標CHILD#1會使用更少的BUFFER_GETS,效率更高。而且之前遊標CHILD#0的is_shareable列標記爲N,不在被共享。
新生成的遊標CHILD#1的is_shareable列標記爲Y,供之後的執行重用。

9.再屢次執行SQL文

--第三次執行
SQL> SELECT  o.order_id, v.product_name
  2  FROM   orders o,
  3         ( SELECT order_id, product_name
  4           FROM   order_items o, product_information p
  5           WHERE  p.product_id = o.product_id
  6           AND    list_price < 50
  7           AND    min_price < 40 ) v
  8  WHERE  o.order_id = v.order_id
  9  ;
 
  ORDER_ID PRODUCT_NAME     
---------- --------------------                             
      2403 Battery - EL     
...
      2401 SPNIX3.3 AU      
 
269 rows selected.
 
Elapsed: 00:00:00.06
SQL> 
 
--查看執行計劃
 
SQL> set line 200
SQL> set pagesize 9999
SQL> 
SQL> select * from table(dbms_xplan.display_cursor(format=>'typical iostats last -cost -bytes'));
 
PLAN_TABLE_OUTPUT           
---------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 1                       
-------------------------------------                       
SELECT  o.order_id, v.product_name FROM   orders o,        ( SELECT
order_id, product_name          FROM   order_items o,       
product_information p          WHERE  p.product_id = o.product_id
   AND    list_price < 50          AND    min_price < 40 ) v WHERE
o.order_id = v.order_id     
 
Plan hash value: 35479787   
 
-------------------------------------------------------------------------------------------------------------------               
| Id  | Operation              | Name                | Starts | E-Rows | E-Time   | A-Rows |   A-Time   | Buffers |               
-------------------------------------------------------------------------------------------------------------------               
|   0 | SELECT STATEMENT       |                     |      1 |        |          |    269 |00:00:00.03 |      61 |               
|   1 |  NESTED LOOPS          |                     |      1 |    313 | 00:00:01 |    269 |00:00:00.03 |      61 |               
|*  2 |   HASH JOIN            |                     |      1 |    313 | 00:00:01 |    269 |00:00:00.02 |      40 |               
|*  3 |    TABLE ACCESS FULL   | PRODUCT_INFORMATION |      1 |     87 | 00:00:01 |     87 |00:00:00.01 |      15 |               
|   4 |    INDEX FAST FULL SCAN| ORDER_ITEMS_UK      |      1 |    665 | 00:00:01 |    665 |00:00:00.01 |      25 |               
|*  5 |   INDEX UNIQUE SCAN    | ORDER_PK            |    269 |      1 |          |    269 |00:00:00.01 |      21 |               
-------------------------------------------------------------------------------------------------------------------               
 
Predicate Information (identified by operation id):         
---------------------------------------------------         
 
   2 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")            
   3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))         
   5 - access("O"."ORDER_ID"="ORDER_ID")                    
 
Note                        
-----                       
   - cardinality feedback used for this statement           
 
 
32 rows selected.
 
Elapsed: 00:00:00.07
 
--查看動態視圖
SQL> ---sql_id:bmh5hb8331u33
SQL> select sql_id,child_number, executions, buffer_gets,plan_hash_value,is_shareable
  2  from v$sql
  3  where sql_id = 'bmh5hb8331u33';
 
SQL_ID        CHILD_NUMBER EXECUTIONS BUFFER_GETS PLAN_HASH_VALUE I
------------- ------------ ---------- ----------- --------------- -
bmh5hb8331u33            0          1        1604      1906736282 N
bmh5hb8331u33            1          2         122        35479787 Y
 
Elapsed: 00:00:00.00
SQL> 
SQL> select sql_id, child_number, USE_FEEDBACK_STATS
  2  from V$SQL_SHARED_CURSOR
  3  where sql_id = 'bmh5hb8331u33';
 
SQL_ID        CHILD_NUMBER U
------------- ------------ -
bmh5hb8331u33            0 Y
bmh5hb8331u33            1 N
 
Elapsed: 00:00:00.00
--第四次執行
SQL> SELECT  o.order_id, v.product_name
  2  FROM   orders o,
  3         ( SELECT order_id, product_name
  4           FROM   order_items o, product_information p
  5           WHERE  p.product_id = o.product_id
  6           AND    list_price < 50
  7           AND    min_price < 40 ) v
  8  WHERE  o.order_id = v.order_id
  9  ;
 
  ORDER_ID PRODUCT_NAME     
---------- --------------------                             
      2403 Battery - EL     
...
      2401 SPNIX3.3 AU      
 
269 rows selected.
 
Elapsed: 00:00:00.05
SQL> 
 --查看執行計劃
SQL> set line 200
SQL> set pagesize 9999
SQL> 
SQL> select * from table(dbms_xplan.display_cursor(format=>'typical iostats last -cost -bytes'));
 
PLAN_TABLE_OUTPUT           
---------------------------------------------------------------------------------------------
SQL_ID  bmh5hb8331u33, child number 1                       
-------------------------------------                       
SELECT  o.order_id, v.product_name FROM   orders o,        ( SELECT
order_id, product_name          FROM   order_items o,       
product_information p          WHERE  p.product_id = o.product_id
   AND    list_price < 50          AND    min_price < 40 ) v WHERE
o.order_id = v.order_id     
 
Plan hash value: 35479787   
 
-------------------------------------------------------------------------------------------------------------------               
| Id  | Operation              | Name                | Starts | E-Rows | E-Time   | A-Rows |   A-Time   | Buffers |               
-------------------------------------------------------------------------------------------------------------------               
|   0 | SELECT STATEMENT       |                     |      1 |        |          |    269 |00:00:00.02 |      61 |               
|   1 |  NESTED LOOPS          |                     |      1 |    313 | 00:00:01 |    269 |00:00:00.02 |      61 |               
|*  2 |   HASH JOIN            |                     |      1 |    313 | 00:00:01 |    269 |00:00:00.01 |      40 |               
|*  3 |    TABLE ACCESS FULL   | PRODUCT_INFORMATION |      1 |     87 | 00:00:01 |     87 |00:00:00.01 |      15 |               
|   4 |    INDEX FAST FULL SCAN| ORDER_ITEMS_UK      |      1 |    665 | 00:00:01 |    665 |00:00:00.01 |      25 |               
|*  5 |   INDEX UNIQUE SCAN    | ORDER_PK            |    269 |      1 |          |    269 |00:00:00.01 |      21 |               
-------------------------------------------------------------------------------------------------------------------               
 
Predicate Information (identified by operation id):         
---------------------------------------------------         
 
   2 - access("P"."PRODUCT_ID"="O"."PRODUCT_ID")            
   3 - filter(("MIN_PRICE"<40 AND "LIST_PRICE"<50))         
   5 - access("O"."ORDER_ID"="ORDER_ID")                    
 
Note                        
-----                       
   - cardinality feedback used for this statement           
 
 
32 rows selected.
 
Elapsed: 00:00:00.02
SQL> 
--查看動態視圖
SQL> 
SQL> ---sql_id:bmh5hb8331u33
SQL> select sql_id,child_number, executions, buffer_gets,plan_hash_value,is_shareable
  2  from v$sql
  3  where sql_id = 'bmh5hb8331u33';
 
SQL_ID        CHILD_NUMBER EXECUTIONS BUFFER_GETS PLAN_HASH_VALUE I
------------- ------------ ---------- ----------- --------------- -
bmh5hb8331u33            0          1        1604      1906736282 N
bmh5hb8331u33            1          3         183        35479787 Y
 
Elapsed: 00:00:00.00
SQL> 
SQL> select sql_id, child_number, USE_FEEDBACK_STATS
  2  from V$SQL_SHARED_CURSOR
  3  where sql_id = 'bmh5hb8331u33';
 
SQL_ID        CHILD_NUMBER U
------------- ------------ -
bmh5hb8331u33            0 Y
bmh5hb8331u33            1 N
 
Elapsed: 00:00:00.00

咱們發現之後的執行都會變成軟解析,使用第二次產生的執行計劃。
經過CFB功能使優化器可以在之後的執行中選擇更優的執行計劃,從獲得更好的執行效率。

CFB的處理流程

下面經過如下流程圖來整體的回顧一下CFB的處理過程。

在下列狀況CBO可能沒法估算出準確的Cardinality,Oracle會啓用CFB功能:

 

1

2

3

?沒有收集表的統計信息,而且dynamic sampling 也沒有開啓;

? 一個表的查詢條件涉及多列,但卻沒有收集擴展的統計信息(extended statistics)

? 查詢條件複雜(好比條件有函數)

針對上述狀況,Oracle會採起以下的CFB流程處理:

 

1

2

3

4

1. SQL文第一次執行時,Oracle會監控操做的實際行數(A-Row),而後對比CBO估算的行數(E-Row)。

2. 若是兩個值相差很大,就記錄實際行數(A-Row),作上標記。

    下次執行時再次進行硬解析,根據實際行數來從新生成執行計劃。

3. 若是兩個值相差不大,CBO就再也不監控這條SQL語句。

相關文章
相關標籤/搜索