利用函式索引,最佳化因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函式索引
- Oracle索引梳理系列(六)- Oracle索引種類之函式索引Oracle索引函式
- 索引壞掉導致ORA-07445索引
- MySQL 因資料型別轉換導致執行計劃使用低效索引MySql資料型別索引
- sql最佳化-錯誤強制型別轉換導致索引失效SQL型別索引
- impdp導致主鍵索引的變化索引
- Mysql 會導致索引失效的情況MySql索引
- 不要再問我 in,exists 走不走索引了索引
- day25-索引和函式及儲存過程索引函式儲存過程
- [20180509]函式索引問題.txt函式索引
- MySQL函式索引及優化MySql函式索引優化
- [20211231]函式索引測試.txt函式索引
- mysql的新建索引會導致insert被lockedMySql索引
- Python Numpy 切片和索引(高階索引、布林索引、花式索引)Python索引
- mysql的唯一索引不會利用change bufferMySql索引
- 常見的導致PG建立索引慢的原因索引
- Elasitcsearch索引最佳化索引
- mysql 拾遺提高(函式、事務、索引)MySql函式索引
- [20190827]函式索引與選擇率.txt函式索引
- [20190918]關於函式索引問題.txt函式索引
- Oracle like、不等於、隱式轉換走索引與不走索引情況Oracle索引
- 一條主鍵索引SQL導致的CPU被打滿索引SQL
- PostgreSQL-亂序插入資料導致索引膨脹SQL索引
- 《PostgreSQL》 索引與最佳化SQL索引
- MySQL的索引最佳化MySql索引
- oracle 索引和不走索引的幾種形式Oracle索引
- SQL優化案例-自定義函式索引(五)SQL優化函式索引
- Oracle優化案例-自定義函式索引(五)Oracle優化函式索引
- 用函式索引構造特殊的約束函式索引
- [20241012]cursor_sharing=force與函式索引.txt函式索引
- 資料型別與函式索引-PostgreSQL篇資料型別函式索引SQL
- 資料型別與函式索引-MySQL篇資料型別函式索引MySql
- 資料型別與函式索引-Oracle篇資料型別函式索引Oracle
- ElasticSearch分片互動過程(建立索引、刪除索引、查詢索引)Elasticsearch索引
- SQL最佳化案例-分割槽索引之無字首索引(六)SQL索引
- MongoDB ( 五 )高階_索引MongoDB索引
- MySQL 函式索引功能終於可以實現了MySql函式索引
- Oracle 19c中基於函式的索引Oracle函式索引
- SQL優化之利用索引排序SQL優化索引排序