LIKE'%...%'通配符查询的PL / SQL性能调优

时间:2011-06-03 15:49:06

标签: sql oracle indexing query-optimization

我们正在使用Oracle 11g数据库 您可能知道或者可能不知道,如果您在字符串前面使用带有“%”的通配符查询,则索引未被使用全表扫描是发生。

看起来似乎没有关于如何改进此类查询的明确建议,但也许您可以根据您的经验分享一些有价值的信息,如何优化以下查询:

SELECT * 
  FROM myTable 
 WHERE UPPER(CustomerName) like '%ABC%' 
    OR UPPER(IndemnifierOneName) like '%ABC%' 
    OR UPPER(IndemnifierTwoName) like '%ABC%';

...其中所有3列的类型为 varchar2(100) ABC 是变量输入参数的值。

@All建议 CONTEX 索引,请注意我的数据每天的任何时间都会更新,并且此索引需要重新同步,因此是一个不错的选择对于 150万行的表格,抱歉。

P.S。我会回答所有答案,所以请保持他们的到来。

5 个答案:

答案 0 :(得分:7)

如前所述,您可以在名称列中添加ctx上下文索引。

假设有少量记录得到更新,1个选项是每天刷新您的索引。 (并在发生时记录)

然后添加lastupdate日期列&正在搜索的表的索引。

应该可以扫描ctx索引以查找大多数旧的未更改数据 并使用传统的LIKE从较小百分比的更新数据中进行选择 e.g:

WHERE (lastupdated<lastrefresh AND contains(name,'%ABC%')) 
   OR (lastupdated>lastrefresh AND name like '%ABC%')

注意:您可能会发现您的查询计划有点精神错乱(很多位图转换为行ID),在这种情况下,将OR的2部分拆分为UNION ALL查询。 e.g

SELECT id FROM mytable   
    WHERE 
    (lastupdate>lastrefresh and name LIKE '%ABC%')
    UNION ALL
    SELECT id FROM mytable   
    WHERE lastupdate<lastrefresh and CONTAINS(name, '%ABC%', 1) > 0

答案 1 :(得分:6)

唯一的优化是不使用该类型的查询,而是使用数据库平台的本机功能:

请参阅Oracle Text:http://www.oracle.com/technetwork/database/enterprise-edition/index-098492.html

SQL Server相关问题的常见答案是全文搜索..很高兴看到Oracle有一些好的或更好的东西。

答案 2 :(得分:3)

UPPER()在任何事情之前杀死你的索引,考虑使用正则表达式。初始%可以避免正常的索引扫描,但并不总是导致全表扫描,而是进入全指数扫描,这比FTS快。

我认为'ABC'是可变的。如果没有,则可以使用函数索引。

答案 3 :(得分:0)

有时这种查询是不可避免的 - 从URL中提取域,或者从带有前缀和后缀的单词中提取根。

您可以使用或不使用自定义标记生成器来使用全文索引。

或者,如果您要搜索的字符串数量有限并且事先已知(例如,您正在处理需要从URL中提取的一组有限的域名),您可以使用确定性函数被索引。

http://www.akadia.com/services/ora_function_based_index_2.html

答案 4 :(得分:-2)

使用Oracle文本但稍微更新的CTXCAT变体 - 此域索引作为插入/更新相关行的事务的一部分进行更新,因此始终是最新的 - 有关详细信息,请参阅Oracle自己的Oracle Text文档。