模糊查詢like優化方式


sql 模糊查詢大概有如下3種方式:

1) select * from test where name like 'lisi%'  --通配符在後面

2) select * from test where name like '%lisi'  --通配符在前面

3) select * from test where name like '%lisi%' --前後都有通配符


在實際工作中常用的爲第3種,在oracle R2中第一種默認就可以走index,下面是對這3種方式的總結:


創建測試表


SQL> create table test as select * from dba_objects;


Table created.


SQL> create index idx_test_owner on test(owner);


Index created.


第一種方式:當%在後面,默認可以走index

SQL> set lines 200 pages 200;

SQL> set autotrace traceonly; 

SQL> select * from test where owner like 'SCOTT%';

19 rows selected.



Execution Plan

----------------------------------------------------------

Plan hash value: 510444911


----------------------------------------------------------------------------------------------

| Id  | Operation     | Name     | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT     |     |  19 | 3933 |   3   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST     |  19 | 3933 |   3   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN     | IDX_TEST_OWNER|  19 |     |   2   (0)| 00:00:01 |

----------------------------------------------------------------------------------------------


第二種方式:當 %在前面

SQL> select * from test where owner like '%SCOTT';      


19 rows selected.



Execution Plan

----------------------------------------------------------

Plan hash value: 1357081020


--------------------------------------------------------------------------

| Id  | Operation    | Name | Rows  | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |     |    39 |  8073 |   339   (1)| 00:00:05 |

|*  1 |  TABLE ACCESS FULL| TEST |    39 |  8073 |   339   (1)| 00:00:05 |

--------------------------------------------------------------------------


TABLE ACCESS FULL,使用hint強制走index,同樣也不會走

SQL> select /*+ index(test idex_test_owner) */ * from test where owner like '%SCOTT';


19 rows selected.



Execution Plan

----------------------------------------------------------

Plan hash value: 1357081020


--------------------------------------------------------------------------

| Id  | Operation  | Name | Rows  | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  | |    39 |  8073 |   339   (1)| 00:00:05 |

|*  1 |  TABLE ACCESS FULL| TEST |    39 |  8073 |   339   (1)| 00:00:05 |

--------------------------------------------------------------------------



優化方式通過創建函數revers index ,如下:


SQL> create index idex_test_owner2 on test(reverse(owner)); 


SQL> select * from test where reverse(owner) like reverse('%SCOTT'); -- 注意like 寫法


19 rows selected.



Execution Plan

----------------------------------------------------------

Plan hash value: 4040724530


------------------------------------------------------------------------------------------------

| Id  | Operation          | Name           | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT        |           |  4354 |   429K|    24 (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| TEST           |  4354 |   429K|    24 (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN        | IDEX_TEST_OWNER2 |   784 |       |     3 (0)| 00:00:01 |

------------------------------------------------------------------------------------------------

19 rows selected.



Execution Plan

----------------------------------------------------------

Plan hash value: 3746695842


------------------------------------------------------------------------------------------------

| Id  | Operation            | Name       | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT        |       |    39 |  8073 |  2533 (1)| 00:00:31 |

|*  1 |  TABLE ACCESS BY INDEX ROWID| TEST       |    39 |  8073 |  2533 (1)| 00:00:31 |

|   2 |   INDEX FULL SCAN    | IDEX_TEST_OWNER2 | 97132 |       |   207 (1)| 00:00:03 |

------------------------------------------------------------------------------------------------ 



第三種方式: 前後都有%

SQL> select /*+ index(test idex_test_owner) */ * from test where owner like '%SCOTT%';


19 rows selected.



Execution Plan

----------------------------------------------------------

Plan hash value: 1357081020


--------------------------------------------------------------------------

| Id  | Operation      | Name | Rows  | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |     |   218 | 22018 |   339   (1)| 00:00:05 |

|*  1 |  TABLE ACCESS FULL| TEST |   218 | 22018 |   339   (1)| 00:00:05 |

--------------------------------------------------------------------------


優化方式:將表模糊查詢的字段和rowid抽取出來創建新表用來縮小表的體積,然後通過rowid關聯查詢原表


SQL> select t.* from test_1 t1 join test t on t1.rid=t.rowid where t1.owner like '%SCOTT%'; 


19 rows selected.



Execution Plan

----------------------------------------------------------

Plan hash value: 2342862650


--------------------------------------------------------------------------------------

| Id  | Operation            | Name   | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT        |     |  67 | 8710 | 141   (1)| 00:00:02 |

|   1 |  NESTED LOOPS        |     |  67 | 8710 | 141   (1)| 00:00:02 |

|*  2 |   TABLE ACCESS FULL        | TEST_1 |  67 | 1943 |  74   (2)| 00:00:01 |

|   3 |   TABLE ACCESS BY USER ROWID| TEST   |   1 | 101 |   1   (0)| 00:00:01 |

--------------------------------------------------------------------------------------


對於新建的表還可以開啓並行,這樣速度還會大大提升,


-- 這樣必須考慮到一個問題就是原表的dml時如何保證兩個表的數據同步,方式很多這裏不講解。


總結:

1)後面有%號,CBO默認可以走index

2)前面有%號,通過create index idx_xx on tab(reverse(xx)),然後sql 改寫爲如下:

   改寫前:

   select * from test where owner like '%SCOTT'

   改寫後:

   select * from test where reverse(owner) like reverse('%SCOTT');

3) 前後都有%,創建新表保存原表的like列和rowid,然後通過rowid關聯查詢,然後sql改寫如下:

   改寫前:

   select * from test where owner like '%SCOTT%';

   改寫後:

   select 原表.* from 新表 t1 join 原表 t2 on t1.rid = t2.rowid where 新表.owner like '%SCOTT%';

   

   


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章