oracle like模糊查詢的優化測試
三種like模糊查詢的優化:
第一種:like 'a%'這種,直接可走索引
第二種:like '%a'這種,需要用reverse反轉函式改寫SQL,再建立函式索引,如下:
改寫前:
select * from test where owner like '%SCOTT'
改寫後:
select * from test where reverse(owner) like reverse('%SCOTT');
第三種:like '%a%'這種的優化,進行如下測試:
原SQL:
SELECT A0.*
FROM g.wp A0
where A0.ptc_str_12TYPEINFOWABCDT like '%中ABCDdddddddd機%';
OS下執行:
export NLS_LANG=AMERICAN_AMERICA.utf8
SQL> set line 1000
SQL> set pagesize 1000
SQL> set autotrace traceonly
SQL> set timing on
SQL> SELECT A0.*
2 FROM g.wp A0
3 where A0.ptc_str_12TYPEINFOWABCDT like '%中ABCDdddddddd機%';
4694 rows selected.
Elapsed: 00:03:47.72
Execution Plan
----------------------------------------------------------
Plan hash value: 1382574215
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 348K| 330M| 323K (1)| 01:04:46 |
|* 1 | TABLE ACCESS FULL| WABCDT | 348K| 330M| 323K (1)| 01:04:46 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("A0"."PTC_STR_12TYPEINFOWABCDT" IS NOT NULL AND
"A0"."PTC_STR_12TYPEINFOWABCDT" LIKE '%中ABCDdddddddd機%')
Statistics
----------------------------------------------------------
29 recursive calls
0 db block gets
1292784 consistent gets
39729 physical reads
0 redo size
3087832 bytes sent via SQL*Net to client
52158 bytes received via SQL*Net from client
4696 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4694 rows processed
為了降低從磁碟中讀取資料對查詢時間的影響 ,再執行第二次:
SQL> SELECT A0.*
2 FROM g.wp A0
3 where A0.ptc_str_12TYPEINFOWABCDT like '%中ABCDdddddddd機%';
4694 rows selected.
Elapsed: 00:00:33.84
Execution Plan
----------------------------------------------------------
Plan hash value: 1382574215
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 348K| 330M| 323K (1)| 01:04:46 |
|* 1 | TABLE ACCESS FULL| WABCDT | 348K| 330M| 323K (1)| 01:04:46 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("A0"."PTC_STR_12TYPEINFOWABCDT" IS NOT NULL AND
"A0"."PTC_STR_12TYPEINFOWABCDT" LIKE '%中ABCDdddddddd機%')
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1292776 consistent gets
0 physical reads
0 redo size
3087832 bytes sent via SQL*Net to client
52158 bytes received via SQL*Net from client
4696 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4694 rows processed
改寫SQL:
SELECT A0.*
FROM g.wp A0
where instr(A0.ptc_str_12TYPEINFOWABCDT,'中ABCDdddddddd機')>0;
SQL> SELECT A0.*
2 FROM g.wp A0
3 where instr(A0.ptc_str_12TYPEINFOWABCDT,'中ABCDdddddddd機')>0;
4694 rows selected.
Elapsed: 00:03:36.91
Execution Plan
----------------------------------------------------------
Plan hash value: 1382574215
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 434K| 412M| 323K (1)| 01:04:46 |
|* 1 | TABLE ACCESS FULL| WABCDT | 434K| 412M| 323K (1)| 01:04:46 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(INSTR("A0"."PTC_STR_12TYPEINFOWABCDT",'中ABCDdddddddd機')>0)
Statistics
----------------------------------------------------------
29 recursive calls
0 db block gets
1292793 consistent gets
39727 physical reads
0 redo size
3087832 bytes sent via SQL*Net to client
52158 bytes received via SQL*Net from client
4696 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4694 rows processed
建立函式索引:
create index g.fx_WABCDT_1 on g.wp(instr(ptc_str_12TYPEINFOWABCDT,'中ABCDdddddddd機')) tablespace gx parallel 16;
alter index g.fx_WABCDT_1 noparallel;
SQL> SELECT A0.*
2 FROM g.wp A0
3 where instr(A0.ptc_str_12TYPEINFOWABCDT,'中ABCDdddddddd機')>0;
4694 rows selected.
Elapsed: 00:00:02.31
Execution Plan
----------------------------------------------------------
Plan hash value: 3331311615
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 434K| 412M| 12577 (1)| 00:02:31 |
| 1 | TABLE ACCESS BY INDEX ROWID| WABCDT | 434K| 412M| 12577 (1)| 00:02:31 |
|* 2 | INDEX RANGE SCAN | FX_WABCDT_1 | 78135 | | 145 (1)| 00:00:02 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(INSTR("PTC_STR_12TYPEINFOWABCDT",'中ABCDdddddddd機')>0)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
9603 consistent gets
0 physical reads
0 redo size
3085926 bytes sent via SQL*Net to client
52158 bytes received via SQL*Net from client
4696 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4694 rows processed
邏輯讀從 1292776減少到9603,執行時間由33.84s降低到02.31s。但若用繫結變數的情況,不適合這種方法。
若用繫結變數的情況:
指定hint:
SELECT /*+index(A0 CLS_INDEX) */ A0.*
FROM WABCDT A0
where A0.ptc_str_12TYPEINFOWTPART like '中ABCDdddddddd機';
Elapsed: 00:00:05.00
Execution Plan
----------------------------------------------------------
Plan hash value: 4025305430
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 348K| 330M| 141K (1)| 00:28:20 |
| 1 | TABLE ACCESS BY INDEX ROWID| WABCDT | 348K| 330M| 141K (1)| 00:28:20 |
|* 2 | INDEX FULL SCAN | CLS_INDEX | 356K| | 44775 (1)| 00:08:58 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("A0"."PTC_STR_12TYPEINFOWTPART" IS NOT NULL AND
"A0"."PTC_STR_12TYPEINFOWTPART" LIKE '中ABCDdddddddd機')
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
55985 consistent gets
0 physical reads
0 redo size
3085926 bytes sent via SQL*Net to client
52158 bytes received via SQL*Net from client
4696 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4694 rows processed
上面有用到index full scan,邏輯讀減少很多,由1292784減少到55985,若所有需要訪問的資料都在記憶體中,那麼執行比較快,上面執行時間為5秒,反之,若需要的資料從磁碟中讀取,是比較慢, 所以採用將索引和表的數全部keep到cache中。
先檢視db_keep_cache_size大小和索引及表的大小,若keep cache不足以存放表和索引,則需要調大引數。
SQL> show parameter keep
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
buffer_pool_keep string
control_file_record_keep_time integer 7
db_keep_cache_size big integer 15G
SQL> col segment_name for a20;
SQL> select segment_name,segment_type,bytes/1024/1024 "size(MB)" from dba_segments where owner='G' and segment_name in ('WABCDT','CLS_INDEX');
SEGMENT_NAME SEGMENT_TYPE size(MB)
-------------------- ------------------ ----------
WABCDT TABLE 10075
CLS_INDEX INDEX 367
將索引和表keep到記憶體中:
alter index g.CLS_INDEX storage(buffer_pool keep);
alter table g.wtpart storage(buffer_pool keep);
alter table g.wtpart cache;
SQL> select index_name,buffer_pool from dba_indexes where index_name='CLS_INDEX';
INDEX_NAME BUFFER_
------------------------------ -------
CLS_INDEX KEEP
SQL> select owner,table_name,CACHE,BUFFER_POOL from dba_tables where table_name='WABCDT' and owner='G';
OWNER TABLE_NAME CACHE BUFFER_
------------------------------ ------------------------------ -------------------- -------
G WABCDT Y KEEP
上面顯示已有正確keep表和索引到cache中。這樣就可確保除第一次外,其它每次訪問的資料都能從記憶體中獲取。
看下count(*)的情況:
SQL> SELECT count(*)
2 FROM WABCDT A0
3 where A0.ptc_str_12TYPEINFOWABCDT like '%中ABCDdddddddd機%';
Elapsed: 00:00:02.04
Execution Plan
----------------------------------------------------------
Plan hash value: 3203503055
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 12209 (2)| 00:02:27 |
| 1 | SORT AGGREGATE | | 1 | 11 | | |
|* 2 | INDEX FAST FULL SCAN| CLS_INDEX | 348K| 3742K| 12209 (2)| 00:02:27 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("A0"."PTC_STR_12TYPEINFOWABCDT" IS NOT NULL AND
"A0"."PTC_STR_12TYPEINFOWABCDT" LIKE '%中ABCDdddddddd機%')
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
46773 consistent gets
0 physical reads
0 redo size
527 bytes sent via SQL*Net to client
524 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
上面用了INDEX FAST FULL SCAN,走索引的地方是conut(*),並不是where條件。