substr函數索引創建測試


技術群里小伙伴,溝通說一條經常查詢的SQL緩慢,單表SQL一個列作為條件,列是int數值類型,索引類型默認創建。

一.SQL文本
substr函數索引創建測試
select *from(select substr(nm,0,17) nm1 from bbm2019) where nm1 in ('55552389655808973')
需求,將上述SQL執行速度加快,目的是走索引。
創建測試表
SQL>create table tt as select * from dba_objects;
SQL> desc tt
 OBJECT_ID                           NUMBER
二.優化思路
2.1 通過修改SQL文本方式
調整前
SQL
> select * from (select substr(object_id,0,4) cc from tt) t where t.cc in ('2559'); -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 870 | 4350 | 347 (1)| 00:00:05 | |* 1 | TABLE ACCESS FULL| TT | 870 | 4350 | 347 (1)| 00:00:05 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(SUBSTR(TO_CHAR("OBJECT_ID"),0,4)='2559') 調整后,使用單行SQL查詢,不使用子查詢 SQL> select substr(object_id,0,4) from tt where substr(object_id,0,4) in ('2559'); -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 870 | 4350 | 347 (1)| 00:00:05 | |* 1 | TABLE ACCESS FULL| TT | 870 | 4350 | 347 (1)| 00:00:05 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(SUBSTR(TO_CHAR("OBJECT_ID"),0,4)='2559') 無效,SQL還是一次全表掃描,只是測試使用。
2.2 調整索引為字符格式,SQL訪問使用%模糊匹配 select substr(nm,0,17) nm1 lrrq from bbm2019 where nm1in like '55552389655808973%'; SQL> create index tt_obje_ind on tt(object_id); SQL> set autotrace on SQL>select object_id from tt where object_id like '25599%'; -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 14 | 182 | 347 (1)| 00:00:05 | |* 1 | TABLE ACCESS FULL| TT | 14 | 182 | 347 (1)| 00:00:05 | --------------------------------------------------------------------------
可以發現,當表字段為數值類型,使用like 字符格式訪問,是無法獲取結果的。
SQL> drop index tt_obje_ind; SQL> create index tt_obje_ind on tt(to_char(object_id)); SQL> select object_id from tt where object_id like '25599%'; ------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 35 | 3 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| TT | 1 | 35 | 3 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | TT_OBJE_IND | 1 | | 2 (0)| 00:00:01 | ------------------------------------------------------------------------------------------- SQL> select object_id from tt where object_id like '2559%'; ------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 11 | 385 | 5 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| TT | 11 | 385 | 5 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | TT_OBJE_IND | 11 | | 2 (0)| 00:00:01 | -------------------------------------------------------------------------------------------

      2 - access(TO_CHAR("OBJECT_ID") LIKE '2559%')
          filter(TO_CHAR("OBJECT_ID") LIKE '2559%')


使用to_char可以將索引存儲格式調整為字符類型,where條件使用%進行查詢可以走索引快速訪問。
SQL> select object_id from tt where object_id='25599'; SQL> select object_id from tt where object_id in '25599'; SQL> select substr(object_id,0,4) from tt where object_id in('2559'); -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 14 | 490 | 347 (1)| 00:00:05 | |* 1 | TABLE ACCESS FULL| TT | 14 | 490 | 347 (1)| 00:00:05 | --------------------------------------------------------------------------
發現使用in =並未走索引!
   1 - filter("OBJECT_ID"=25599) 可以發現並未顯示to_char
此處,第一次發現oracle隱患轉換的優先級,可能會影想是否走索引,由於oracle to_number優先級大於to_char因此即使我們寫法'xx'字符數值等值查詢,
oracle自動轉換為數值類型,由於索引為字符類型,因此無法走索引。
SQL> select object_id from tt where to_char(object_id)='25599';  

-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 870 | 23490 | 72 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TT | 870 | 23490 | 72 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | TT_OBJE_IND | 348 | | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access(TO_CHAR("OBJECT_ID")='25599')

不創建函數索引,直接使用to_char類,查詢條件

2.3 創建Substr函數索引
SQL
> drop index tt_obje_ind;
SQL
> create index tt_obje_ind on tt(substr(object_id,0,4));
SQL
> select substr(object_id,0,4) from tt where substr(object_id,0,4) in ('2559');
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11 | 110 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| TT_OBJE_IND | 11 | 110 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access(SUBSTR(TO_CHAR("OBJECT_ID"),0,4)='2559')
SQL
> create index tt_obje_ind on tt(substr(to_char(object_id),0,4));
SQL
> select substr(object_id,0,4) from tt where substr(object_id,0,4) in ('2559');
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 11 | 110 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| TT_OBJE_IND | 11 | 110 | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access(SUBSTR(TO_CHAR("OBJECT_ID"),0,4)='2559')
創建substr函數索引,oracle自動會to_char轉換,可以顯示創建索引語法加上 (可不加,規范語法加上最好~)
on tt(substr(to_char(object_id),0,4)); 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM