优化寻找子字符串匹配的Oracle查询的好方法是什么?

时间:2009-09-29 00:54:13

标签: sql performance oracle oracle10g query-optimization

我在一个非分区的Oracle表中有一个列,定义为VARCHAR2(50);该列具有标准的b树索引。我想知道是否有一种最佳方式来查询此列以确定它是否包含给定值。这是当前的查询:

SELECT * FROM my_table m WHERE m.my_column LIKE '%'||v_value||'%';

我查看了Oracle Text,但对于这么小的专栏来说,这似乎有些过分。但是,此表中有数百万条记录,因此寻找子字符串匹配所花费的时间比我想要的多。还有更好的方法吗?

6 个答案:

答案 0 :(得分:2)

没有

该查询是表扫描。如果v_value是一个实际的单词,那么你可能想要查看Oracle Text或一个简单的倒排索引方案,你可以自己动手。但就是这样,它太可怕了。

答案 1 :(得分:2)

Oracle Text涵盖了许多不同的方法,并非所有方法都是重量级的。由于您的列非常小,您可以使用CTXCAT索引对其进行索引。

SELECT * FROM my_table m 
WHERE catsearch(m.my_column, v_value, null) > 0
/

与其他类型的Text索引不同,CTXCAT索引是事务性的,因此它们不需要同步。这些索引占用了大量空间,但您必须为提高性能付出一些代价。

Find out more.

答案 2 :(得分:1)

您有三种选择:

重新定义问题的最简单方法是说列必须以搜索词开头(因此丢失第一个%),然后使用索引。

另一种方法是说搜索从单词边界开始(因此“est”将匹配“估计”但不匹配“测试”)。 MySQL(MyISAM)和SQL Server具有像这样匹配的功能。不确定Oracle是否这样做。如果不是,您可以创建一个要搜索的单词查找表而不是列本身,您可以在触发器上填充该表。

答案 3 :(得分:1)

您可以使用REGEXP_LIKE函数在列上放置基于函数的索引。您可能需要使用case语句创建fbi以返回带有匹配项的'1',因为布尔返回函数似乎在fbi中无效。

这是一个例子。

创建索引:

CREATE INDEX regexp_like_on_myCol ON my_table (
      CASE WHEN REGEXP_LIKE(my_column, '[static exp]', 'i') 
           THEN 1
           END);

然后使用它,而不是:

SELECT * FROM my_table m WHERE m.my_column LIKE '%'||v_value||'%';

您需要执行以下查询:

SELECT * FROM my_table m WHERE (
      CASE WHEN REGEXP_LIKE(m.my_column, '[static exp]', 'i')
           THEN 1
           END) IS NOT NULL;

这种方法的一个重要缺点是,您需要在创建索引时知道'[静态exp]'。如果您在执行即席查询时寻求性能提升,则可能不适合您。

正如功能名称所示,奖励是您有机会使用正则表达式创建此索引,这最终可能是一个强大的工具。当项目添加到表格时,而不是在搜索过程中,将进行评估。

答案 4 :(得分:1)

您可以尝试INSTR

...WHERE INSTR(m.my_column, v_value) > 0

我无法访问Oracle进行测试和测试通过通配符找出它是否比LIKE更快。

答案 5 :(得分:1)

对于最常见的情况,您事先并不知道要搜索的字符串,那么您希望的最佳访问路径是快速全索引扫描。您必须专注于保持索引尽可能小,当然可能有它自己的问题,如果数据的基数不是很高,可以查看压缩索引。