zoukankan      html  css  js  c++  java
  • 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的办法定期重建索引。

  • 相关阅读:
    大学毕业4年-回顾和总结(1)-钱,金钱观
    VR开发中性能问题—OculusWaitForGPU
    动态规划(一)
    POJ 2229 Sumsets
    hihoCoder #1122 : 二分图二•二分图最大匹配之匈牙利算法
    hihoCoder #1127 : 二分图二·二分图最小点覆盖和最大独立集
    hihoCoder #1121 : 二分图一•二分图判定
    HDU 1978 How many ways
    POJ1579 Function Run Fun
    POJ 2081 Recaman's Sequence
  • 原文地址:https://www.cnblogs.com/itzhoucong/p/11647496.html
Copyright © 2011-2022 走看看