Oracle 模糊查詢 優化


模糊查詢是數據庫查詢中經常用到的,一般常用的格式如下:

(1)字段  like '%關鍵字%'   字段包含"關鍵字“的記錄   即使在目標字段建立索引也不會走索引,速度最慢  

(2)字段  like '關鍵字%'      字段以"關鍵字"開始的記錄   可以使用到在目標字段建立的升序索引

(3)字段 like '%關鍵字'      字段以"關鍵字“結束的記錄    可以使用到目標字段建立的降序索引

 

對於無法使用索引的 '%關鍵字%' 模式,有沒有辦法優化呢,答案是肯定的,

在ORacle中提供了instr(strSource,strTarget)函數,比使用'%關鍵字%'的模式效率高很多。

instr函數說明:

INSTR

  (源字符串, 目標字符串, 起始位置, 匹配序號)

  在Oracle/PLSQL中,instr函數返回要截取的字符串在源字符串中的位置。只檢索一次,就是說從字符的開始

  到字符的結尾就結束。

  語法如下:

  instr( string1, string2 [, start_position [, nth_appearance ] ] )

  參數分析:

  string1

  源字符串,要在此字符串中查找。

  string2

  要在string1中查找的字符串.

  start_position

  代表string1 的哪個位置開始查找。此參數可選,如果省略默認為1. 字符串索引從1開始。如果此參數為正,從左到右開始檢索,如果此參數為負,從右到左檢索,返回要查找的字符串在源字符串中的開始索引。

  nth_appearance

  代表要查找第幾次出現的string2. 此參數可選,如果省略,默認為 1.如果為負數系統會報錯。

  注意:

  如果String2在String1中沒有找到,instr函數返回0.

  示例:

  SELECT instr('syranmo','s') FROM dual; -- 返回 1

  SELECT instr('syranmo','ra') FROM dual;  -- 返回 3

  SELECT instr('syran mo','a',1,2) FROM dual;  -- 返回 0

  對比:

   instr(title,'手冊')>0  相當於  title like '%手冊%'

   instr(title,'手冊')=1  相當於  title like '手冊%'

   instr(title,'手冊')=0  相當於  title not like '%手冊%'

模糊查詢優化:

  了解了instr函數的用法,優化就變得簡單了,例如 %關鍵字%   等同於  instr(字段,'關鍵字')>0 

 

實際應用:

t表中將近有1100萬數據,很多時候,我們要進行字符串匹配,在SQL語句中,我們通常使用like來達到我們搜索的目標。但經過實際測試發現,like的效率與instr函數差別相當大。下面是一些測試結果:

SQL> set timing on
SQL> select count(*) from t where instr(title,'手冊')>0;

  COUNT(*)
----------
     65881

Elapsed: 00:00:11.04
SQL> select count(*) from t where title like '%手冊%';

  COUNT(*)
----------
     65881

Elapsed: 00:00:31.47
SQL> select count(*) from t where instr(title,'手冊')=0;

  COUNT(*)
----------
  11554580

Elapsed: 00:00:11.31
SQL> select count(*) from t where title not like '%手冊%';

  COUNT(*)
----------
  11554580

另外,我在結另外一個2億多的表,使用8個並行,使用like查詢很久都不出來結果,但使用instr,4分鍾即完成查找,性能是相當的好。這些小技巧用好,工作效率提高不少。通過上面的測試說明,ORACLE內建的一些函數,是經過相當程度的優化的。

 

instr(title,’aaa’)>0 相當於like

instr(title,’aaa’)=0 相當於not like

 

特殊用法:

 

select   id, name from users where instr('101914, 104703', id) > 0; 
  它等價於 
select   id, name from users where id = 101914 or id = 104703;

 

 

 

使用Oracleinstr函數與索引配合提高模糊查詢的效率

一般來說,在Oracle數據庫中,我們對tb表的name字段進行模糊查詢會采用下面兩種方式:
1.select * from tb where name like '%XX%';
2.select * from tb where instr(name,'XX')>0;

若是在name字段上沒有加索引,兩者效率差不多,基本沒有區別。

為提高效率,我們在name字段上可以加上非唯一性索引:
create index idx_tb_name on tb(name);

這樣,再使用

select * from tb where instr(name,'XX')>0;

這樣的語句查詢,效率可以提高不少,表數據量越大時兩者差別越大。但也要顧及到name字段加上索引后DML語句會使索引數據重新排序的影響。

 

 

另一種未知的方案:

有人說了用全文索引,我看了,步驟挺麻煩,但是是個不錯的方法,留着備用:

http://sandish.itpub.net/post/4899/464369

對cmng_custominfo 表中的address字段做全文檢索:
1,在oracle9201中需要創建一個分詞的東西:

BEGIN
ctx_ddl.create_preference ('SMS_ADDRESS_LEXER', 'CHINESE_LEXER');
--ctx_ddl.create_preference ('my_lexer', 'chinese_vgram_lexer'); 不用
end;

2,創建全文檢索:

CREATE INDEX INX_CUSTOMINFO_ADDR_DOCS ON cmng_custominfo(address) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('LEXER SMS_ADDRESS_LEXER');

3,查詢時候,使用:

select * from cmng_custominfo where contains (address, '金色新城')>1;

4,需要定期進行同步和優化:
同步:根據新增記錄的文本內容更新全文搜索的索引。

begin
ctx_ddl.sync_index('INX_CUSTOMINFO_ADDR_DOCS');
end;

優化:根據被刪除記錄清除全文搜索索引中的垃圾

begin
ctx_ddl.optimize_index('INX_CUSTOMINFO_ADDR_DOCS', 'FAST');
end;

5,采用job做步驟4中的工作:

1)該功能需要利用oracle的JOB功能來完成
因為oracle9I默認不啟用JOB功能,所以首先需要增加ORACLE數據庫實例的JOB配置參數:
job_queue_processes=5
重新啟動oracle數據庫服務和listener服務。

2)同步 和 優化
--同步 sync:
variable jobno number;
BEGIN
DBMS_JOB.SUBMIT(:jobno,'ctx_ddl.sync_index(''INX_CUSTOMINFO_ADDR_DOCS'');', SYSDATE, 'SYSDATE + (1/24/4)');
 commit;
END;

--優化
variable jobno number;
begin
 DBMS_JOB.SUBMIT(:jobno,'ctx_ddl.optimize_index(''INX_CUSTOMINFO_ADDR_DOCS'',''FULL'');', SYSDATE, 'SYSDATE + 1');
 commit;
END;

其中, 第一個job的SYSDATE + (1/24/4)是指每隔15分鍾同步一次,第二個job的SYSDATE + 1是每隔1天做一次全優化。具體的時間間隔,可以根據應用的需要而定

6,索引重建
重建索引會刪除原來的索引,重新生成索引,需要較長的時間。
重建索引語法如下:
ALTER INDEX INX_CUSTOMINFO_ADDR_DOCS REBUILD;

據網上一些用家的體會,oracle重建索引的速度也是比較快的,有一用家這樣描述:

Oracle 的全文檢索建立和維護索引要比ms sql server都要快得多,筆者的65萬記錄的一個表建立索引只需要20分鍾,同步一次只需要1分鍾。
因此,也可以考慮用job的辦法定期重建索引。


免責聲明!

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



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