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的办法定期重建索引。

参考资料:
1,http://blog.csdn.net/yurenjia/archive/2007/04/08/1556306.aspx
2,http://topic.csdn.net/u/20080117/23/34004f4a-4989-47ef-8764-0b7e3bf737a7.html
3,http://tenwe.com/tech/database/oracle/200702/content_561_4.shtml
4,http://www.knowsky.com/389357.html
5,http://yangtingkun.itpub.net/post/468/195520
6,http://bbs.zdnet.com.cn/archiver/tid-120474.html
7,http://bbs.51cto.com/archiver/tid-26270.html
8,http://oracle.chinaitlab.com/exploiture/720104_3.html
9,http://www.33kuai.cn/html/shujuku/20080126/5314_2.html
10,http://www.xrss.cn/Dev/DataBase/20084218963.Html

时间: 2024-10-03 09:10:23

Oracle 模糊查询 优化的相关文章

Oracle 模糊查询方法

在这个信息量剧增的时代,如何帮助用户从海量数据中检索到想要的数据,模糊查询是必不可少的.那么在Oracle中模糊查询是如何实现的呢? 一.我们可以在where子句中使用like关键字来达到Oracle模糊查询的效果:在Where子句中,可以对datetime.char.varchar字段类型的列用Like关键字配合通配符来实现模糊查询,以下是可使用的通配符: (1)% :零或者多个字符,使用%有三种情况 字段 like '%关键字%'字段包含"关键字"的记录 字段 like '关键字%

oracle 模糊查询 (处理jsp页面传过来的条件)

oracle数据模糊查询的语句: SELECT m.MUSICID,m.MUSICNAME,m.MUSICPICTURE,m.MUSICLYRICS,m.MUSICINSTRUCTION FROM MUSIC m where m.musicname like '%见%'; 本来 我是打算通过 实体类(entity),数据访问层(dao),业务逻辑层(biz)封装后 在Action中调用模糊查询的方法  来实现 根据我输入的 关键字 来进行模糊查询. 试了好多SQL都没有用  提示 为 "非正确语

Oracle模糊查询CONCAT参数个数无效

在使用MyBatis操作Oracle数据库的时候,写模糊查询突然发现原本在MySql中正确的代码,在Oracle中报错,参数个数无效 <if test="empId!=null and empId!=''"> and e.empId like CONCAT('%',#{empId},'%') </if> 异常信息: 经过查阅数个资料后得知Oracle的CONCAT函数不像MySql那样支持三个参数的拼接,需要把SQL语句修正为: and e.empId like

mysql 百万级数据的模糊查询 优化 笔记

最近老大给了一个需求,是要写一个姓名的模糊查询. 问题很简单,难度在于这张表有将近500W条数据. 如果要做中文的模糊查询,效率简直惨不忍睹. 网上查了一下资料,发现全文索引挺符合我的需要的. 结果,使用下来.其实并不太符合我的要求. 全文索引的最小单位是词,如果不是在 in boolean mode 下是没办法 查询的 其次,全文索引只支持 半模糊查询,我所谓的半模糊就是  xx like 'xx%' 如果使用全模糊查询,建完索引之后,用 like 或者用 regexp 在常用关键词的时候 确

oracle模糊查询简述

--like模糊查询,通配符:'%'表示代替一个或多个字符,'_'表示代替一个字符select * from v_test where v_name like '_BCE%'; 转义字符:可以把通配符('%','_')转义为字符,而非其原意 select * from v_test where v_name like '\_BCE%' escape '\';--也可以把其他字符声明为转义字符select * from tt where v_name like 'S_BCE%' escape 'S

oracle 模糊查询中的转义字符用法

drop view aaa; create view aaa as select '_BCDE' A FROM DUAL UNION ALL SELECT 'ABCDE' FROM DUAL UNION ALL SELECT 'ACBDE' FROM DUAL; SELECT A FROM AAA WHERE A LIKE '_BCD%'; select a from aaa where a like '\_BCD%' ESCAPE '\'; ESCAPE 后面的字符表示是一个检索字符, 字符串

oracle 模糊查询忽略大小写

select * from c_table t where upper(t.name) like '%F%';--将字段全转成大写 select * from c_table t where lower(t.name) like '%f%';--将字段全转成小写 select * from c_table t where t.name like upper('%f%') or t.name like lower('%F%');

LinqToEntity模糊查询的方法选择

LinqToEntity针对oracle模糊查询 方法:Contains() 转换出来的sql是  like  关键字 方法:IndexOf()  转换出来的sql是  instr()  函数 like 和 instr() 方法对于模糊查询的效率 有时有很大的差异,使用时可根据需要选择

回味Oracle的模糊查询

select table_name,tablespace_name,temporary from user_tables where table_name like '%PROV%' 分析: table_name:表名(varchar2(30)); tablespace_name:存储表名的表空间(varchar2(30)): temporary:是否为临时表(varchar2(1)). 4种通配符的含义 % 表示零个或多个字符 _ 表示单个字符 [] 表示范围[a-f]或集合[abcdef]的