【效能優化】執行計劃與直方圖

楊奇龍發表於2011-10-15
在Oracle中直方圖是一種對資料分佈質量情況進行描述的工具。它會按照某一列不同值出現數量多少,以及出現的頻率高低來繪製資料的分佈情況,以便能夠指導優化器根據資料的分佈做出正確的選擇。在某些情況下,表的列中的數值分佈將會影響優化器使用索引還是執行全表掃描的決策。當 where 子句的值具有不成比例數量的數值時,將出現這種情況,使得全表掃描比索引訪問的成本更低。這種情況下如果where 子句的過濾謂詞列之上上有一個合理的正確的直方圖,將會對優化器做出正確的選擇發揮巨大的作用,使得SQL語句執行成本最低從而提升效能。
根據dba_objects建立一個傾斜列的表。並在嚴重傾斜的列上建立索引
YANG@yangdb-rac3> create table bind as select * from dba_objects;
Table created.
YANG@yangdb-rac3> update bind set status='INVALID' WHERE WNER='SCOTT';
6 rows updated.
YANG@yangdb-rac3> create index bind_idx on bind(status);
Index created.
收集表和索引的資訊。
YANG@yangdb-rac3> exec dbms_stats.gather_table_stats(user,'BIND',cascade=>true);
PL/SQL procedure successfully completed.
YANG@yangdb-rac3> set autot trace exp
檢視其執行計劃,發現執行計劃並沒有走索引而是全表掃描
YANG@yangdb-rac3> select owner from bind where status='INVALID';
Execution Plan
----------------------------------------------------------
Plan hash value: 3586145581
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      | 36374 |   461K|   291   (1)| 00:00:04 |
|*  1 | TABLE ACCESS FULL| BIND | 36374 |   461K|   291   (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("STATUS"='INVALID')
為索引列的兩個值建立直方圖。
YANG@yangdb-rac3> EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'BIND',method_opt => 'FOR ALL INDEXED COLUMNS  SIZE 2');
PL/SQL procedure successfully completed.
YANG@yangdb-rac3> select owner from bind where status='INVALID';
Execution Plan
----------------------------------------------------------
Plan hash value: 4106465825
----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |    13 |   169 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| BIND     |    13 |   169 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | BIND_IDX |    13 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("STATUS"='INVALID')

但是當對於收集直方圖的列在sql 語句where 中使用繫結變數的時候:執行計劃改變了!沒有選擇索引而是全表掃描。
YANG@yangdb-rac3> variable val varchar2(10); 
YANG@yangdb-rac3> exec :val :='VALID';
PL/SQL procedure successfully completed.
YANG@yangdb-rac3> select owner from bind where status= :val;
Execution Plan
----------------------------------------------------------
Plan hash value: 3586145581
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      | 36374 |   461K|   291   (1)| 00:00:04 |
|*  1 |  TABLE ACCESS FULL| BIND | 36374 |   461K|   291   (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("STATUS"=:VAL)
YANG@yangdb-rac3> exec :val :='INVALID';
PL/SQL procedure successfully completed.
YANG@yangdb-rac3> 
YANG@yangdb-rac3> select owner from bind where status= :val;
Execution Plan
----------------------------------------------------------
Plan hash value: 3586145581
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      | 36374 |   461K|   291   (1)| 00:00:04 |
|*  1 |  TABLE ACCESS FULL| BIND | 36374 |   461K|   291   (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
--------------------------------------------------
   1 - filter("STATUS"=:VAL)
YANG@yangdb-rac3> alter system flush shared_pool;
System altered.
避免bind 變數,第一次執行時使用 INVALID 
YANG@yangdb-rac3> variable val varchar2(10);
YANG@yangdb-rac3> exec :val :='INVALID';
PL/SQL procedure successfully completed.
YANG@yangdb-rac3> select owner from bind where status= :val;
Execution Plan
----------------------------------------------------------
Plan hash value: 3586145581
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      | 36374 |   461K|   291   (1)| 00:00:04 |
|*  1 |  TABLE ACCESS FULL| BIND | 36374 |   461K|   291   (1)| 00:00:04 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("STATUS"=:VAL)
YANG@yangdb-rac3> select owner from bind where status= 'INVALID';
Execution Plan
----------------------------------------------------------
Plan hash value: 4106465825
----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |    13 |   169 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| BIND     |    13 |   169 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | BIND_IDX |    13 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("STATUS"='INVALID')
其實直方圖具有一下幾個使用限制
1 all predicates on the column use bind variables 
2 the column data is uniformly distributed 
3 the column is not used in WHERE clauses of queries 
4 the column is unique and is used only with equality predicates 
當sql 語句遇到上述情況,收集直方圖資訊是無效的。
參考文章:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22664653/viewspace-709190/,如需轉載,請註明出處,否則將追究法律責任。

相關文章