我在一个非分区的Oracle表中有一个列,定义为VARCHAR2(50);该列具有标准的b树索引。我想知道是否有一种最佳方式来查询此列以确定它是否包含给定值。这是当前的查询:
SELECT * FROM my_table m WHERE m.my_column LIKE '%'||v_value||'%';
我查看了Oracle Text,但对于这么小的专栏来说,这似乎有些过分。但是,此表中有数百万条记录,因此寻找子字符串匹配所花费的时间比我想要的多。还有更好的方法吗?
答案 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索引是事务性的,因此它们不需要同步。这些索引占用了大量空间,但您必须为提高性能付出一些代价。
答案 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)
答案 5 :(得分:1)
对于最常见的情况,您事先并不知道要搜索的字符串,那么您希望的最佳访问路径是快速全索引扫描。您必须专注于保持索引尽可能小,当然可能有它自己的问题,如果数据的基数不是很高,可以查看压缩索引。