2011-06-03 62 views
9

我们正在使用Oracle 11g数据库。
正如您可能会或可能不知道,如果您在字符串前面使用带有“%”的通配符查询,则不会使用索引列全表扫描正在发生。LIKE'%...%'的PL/SQL性能调优通配符查询

它看起来像有没有关于如何提高这种查询的一个明确的建议,但也许你可以分享您的经验,就如何优化以下查询一些有价值的信息:

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.我会积极回答每一个问题,所以请保持他们的到来。

+2

不要做那种查询吗?它必须进行表扫描,因为前面的'%'表示在该字段的前面可能有任何东西。这意味着它需要搜索该字段每一行的内容。 – JNK 2011-06-03 15:53:25

+0

感谢,不幸的是它不是一个选项 – Tsar 2011-06-03 15:55:45

+0

首先在字段CustomerName,IndemnifierOneName,IndemnifierTwoName上添加一个基于函数的索引,然后按照本文的建议操作:http://www.dba-oracle.com/t_sql_like_clause_index_usage.htm – Chandu 2011-06-03 15:56:04

回答

5

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

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

然后将最新更新日期列&索引添加到正在搜索的表中。

应该可以扫描你的CTX指数为广大老不变的数据 并使用一般传统LIKE 例如,从更新的数据的很小比例选择:

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

注意:您可能会发现在这种情况下,您的查询计划会带来一点心理上的问题(将大量位图转换为行ID),将OR的2个部分分解为UNION ALL查询。 如

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 
6

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

见甲骨文文字:http://www.oracle.com/technetwork/database/enterprise-edition/index-098492.html

为SQL Server有关问题的共同答案应该是全部文本搜索..很高兴看到Oracle有一些好或更好的东西。

+0

+1:但是乔的回答至少是一分钟 – 2011-06-03 16:11:38

+0

@OMG小马:你和你的事实......谢谢:) – Fosco 2011-06-03 16:12:31

+0

我这么迂腐:) – 2011-06-03 16:20:25

0

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

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

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

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

2

UPPER()是什么,之前杀死你的指标,可以考虑使用正则表达式。最初的%可能会避免正常的索引扫描,但并不总是导致全表扫描,而是导致比FTS更快的全索引扫描。

我想'ABC'是可变的。如果没有,功能指数是要走的路。

+0

是的,它是一个变量,我会编辑q要注意的是,谢谢。在UPPER(CUSTOMERNAME)上有一个索引,根据解释计划它没有被使用。 – Tsar 2011-06-06 10:48:23

+0

对于快速全面扫描,查询中的每一列都应该被索引覆盖。您可以尝试“SELECT UPPER(CustomerName) FROM myTable WHERE UPPER(CustomerName)like'%ABC%'”来查看结果是否为FFS? – Samuel 2011-06-06 11:08:27

+0

对不起,我想这不使用索引:SELECT语句,GOAL = ALL_ROWS \t \t \t成本= 1930 \t基数= 78206个\t字节= 1173090 索引全扫描\t对象所有者= POSOWN \t对象名称= XIF20CR_PROPOSALSEARCH \t成本= 1930 \t基数= 78206 \t字节= 1173090 – Tsar 2011-06-06 13:20:34

-2

使用Oracle文本,但稍微新CTXCAT变化 - 这个域的索引更新为插入交易的一部分/更新问题记录,因此始终保持最新 - 请参阅Oracle自己Oracle Text文档获取详细信息。