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%';