利用函式索引,最佳化因cluster factor過高導致不走索引一例
在生產環境出現一件怪事,一個查詢,按照日期生成查詢,而且,查詢的結果集佔總資料量的比重也很小,但這個查詢確不走索引掃描,見下例:
SQL> select count(*) from ttm_temp_order t;
COUNT(*)
----------
729465
總行數為70多萬條
SQL> select count(*) from ttm_temp_order t where t.order_time>=trunc(sysdate)-2;
COUNT(*)
----------
6076
查詢兩天內的資料只有6000多條,理應走索引掃描
SQL> exec dbms_stats.gather_table_stats(user,'TTM_TEMP_ORDER',null,null,method_opt => 'for all indexed columns size 254',cascade => true,degree => 4);
PL/SQL procedure successfully completed.
統計資訊保證是最新的
SQL> set autot trace exp stat
SQL> select * from ttm_temp_order t where t.order_time>=trunc(sysdate)-2;
6076 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 256603396
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7116 | 1660K| 5386 (1)| 00:01:05 |
|* 1 | TABLE ACCESS FULL| TTM_TEMP_ORDER | 7116 | 1660K| 5386 (1)| 00:01:05 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("T"."ORDER_TIME">=TRUNC()
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
24680 consistent gets
0 physical reads
0 redo size
1214061 bytes sent via SQL*Net to client
4924 bytes received via SQL*Net from client
407 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
6076 rows processed
居然走的是全表掃描。強制索引掃描,看看邏輯讀
SQL> select /*+ index(t) */ * from ttm_temp_order t where t.order_time>=trunc(sysdate)-2;
6076 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 760559715
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7116 | 1660K| 6745 (1)| 00:01:21 |
| 1 | TABLE ACCESS BY INDEX ROWID| TTM_TEMP_ORDER | 7116 | 1660K| 6745 (1)| 00:01:21 |
|* 2 | INDEX RANGE SCAN | TTM_TEMP_ORDER_IDX1 | 7116 | | 20 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T"."ORDER_TIME">=TRUNC()
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
6445 consistent gets
0 physical reads
0 redo size
1543059 bytes sent via SQL*Net to client
4924 bytes received via SQL*Net from client
407 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
6076 rows processed
比全表掃描少了不少。那為什麼Oracle不選擇更好的索引掃描呢?這裡有一個cluster factor的概念
有興趣的朋友可以看一下官方文件:
SQL> select t.index_name,t.num_rows,t.clustering_factor from user_indexes t where t.index_name='TTM_TEMP_ORDER_IDX1';
INDEX_NAME NUM_ROWS CLUSTERING_FACTOR
------------------------------ ---------- -----------------
TTM_TEMP_ORDER_IDX1 729467 689050
cluster factor確實不小,這就是Oracle不選擇索引掃描的原因。那為什麼這裡的cluster factor這麼高呢?原因在於這個欄位儲存的是詳細的時間資訊,精確至秒,因此,按照cluster factor的計算方法,cluster factor確實比較高。
那麼有什麼辦法能夠讓Oracle走索引掃描呢?根據這個案例的特性,我們可以建立一個函式索引,將時間部分去除,只保留日期部分,這樣,應該可以降低cluster factor。建立索引過程略
SQL> select * from ttm_temp_order t where to_char(t.order_time,'YYYY-MM-DD')>=to_char(sysdate-2,'YYYY-MM-DD');
6076 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 2246974986
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6073 | 1417K| 388 (0)| 00:00:05 |
| 1 | TABLE ACCESS BY INDEX ROWID| TTM_TEMP_ORDER | 6073 | 1417K| 388 (0)| 00:00:05 |
|* 2 | INDEX RANGE SCAN | TTM_TEMP_ORDER_IDX3 | 6073 | | 20 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(TO_CHAR(INTERNAL_FUNCTION("ORDER_TIME"),'YYYY-MM-DD')>=TO_CHAR(
YYY-MM-DD'))
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1335 consistent gets
0 physical reads
0 redo size
1212195 bytes sent via SQL*Net to client
4924 bytes received via SQL*Net from client
407 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
6076 rows processed
Oracle正確的選擇了索引掃描,並且,因為cluster factor的降低,連帶著consistent gets也有明顯的降低。
[@more@]來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/19423/viewspace-1056056/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 複合索引與函式索引優化一例索引函式優化
- 高效的SQL(隱式轉換導致不走索引)SQL索引
- CHAR型別函式索引導致結果錯誤型別函式索引
- 避免在WHERE條件中,在索引列上進行計算或使用函式,因為這將導致索引不被使用索引函式
- 高效的SQL(函式索引優化VIEW一例)SQL函式索引優化View
- Oracle隱式型別轉換導致索引失效Oracle型別索引
- 函式索引陷阱函式索引
- oracle函式索引Oracle函式索引
- SQL最佳化案例-自定義函式索引(五)SQL函式索引
- 函式索引使用細節——自定義函式的索引化函式索引
- sql中使用函式導致cost高SQL函式
- Oracle之函式索引Oracle函式索引
- 說說函式索引函式索引
- 索引中使用函式索引函式
- Oracle索引梳理系列(六)- Oracle索引種類之函式索引Oracle索引函式
- 多餘索引導致explain錯誤索引AI
- ORACLE 大小寫導致找不到索引Oracle索引
- Clustering Factor——索引的成本指標索引指標
- MySQL 因資料型別轉換導致執行計劃使用低效索引MySql資料型別索引
- sql最佳化-錯誤強制型別轉換導致索引失效SQL型別索引
- 索引@oracel索引技術之索引最佳化索引
- 基於函式的索引函式索引
- 函式索引的問題函式索引
- deterministic function 函式索引Function函式索引
- 函式索引的儲存函式索引
- SQL優化--函式索引SQL優化函式索引
- sequence 和索引函式呼叫索引函式
- Mysql 會導致索引失效的情況MySql索引
- Oracle中利用函式索引處理資料傾斜案例Oracle函式索引
- 利用函式索引解決複雜的約束問題函式索引
- CLUSTERING_FACTOR、回表、資料分佈傾斜走全表還是索引索引
- 【隱式轉換】注意隱式轉換將導致索引無法使用索引
- SQL最佳化中索引列使用函式之靈異事件SQL索引函式事件
- day25-索引和函式及儲存過程索引函式儲存過程
- MySQL函式索引及優化MySql函式索引優化
- Oracle基於函式的索引Oracle函式索引
- 索引ROWID轉換函式索引函式
- ddl 導致分割槽表全域性索引unusable索引