【问题标题】:What is a good way to optimize an Oracle query looking for a substring match?什么是优化查找子字符串匹配的 Oracle 查询的好方法?
【发布时间】:2010-12-02 04:21:54
【问题描述】:

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

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

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

【问题讨论】:

    标签: sql performance oracle oracle10g query-optimization


    【解决方案1】:

    没有。

    该查询是表扫描。如果 v_value 是一个实际的单词,那么您可能非常想查看 Oracle Text 或您自己推出的简单倒排索引方案。但就目前而言,这太可怕了。

    【讨论】:

    • 从技术上讲,查询将涉及 FULL 扫描,但不一定是表;如果存在合适的索引,它可以进行索引快速全扫描。在这种情况下,索引扫描可能比 FTS 更快,尤其是当列中有很多 NULL 时。
    【解决方案2】:

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

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

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

    Find out more.

    【讨论】:

      【解决方案3】:

      你有三个选择:

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

      另一种方法是说搜索从单词边界开始(因此“est”将匹配“estimate”而不是“test”)。 MySQL (MyISAM) 和 SQL Server 具有可以像这样进行匹配的函数。不确定甲骨文是否有。如果不是,您可以创建要搜索的单词查找表而不是列本身,并且您可以在触发器上填充该表。

      【讨论】:

        【解决方案4】:

        您可以使用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]”。如果您希望在执行即席查询时提高性能,这可能不适合您。

        正如函数名称所示,一个好处是您有机会使用正则表达式创建此索引,这最终可能是一个强大的工具。当项目被添加到表中时,将进行评估命中,而不是在搜索期间。

        【讨论】:

          【解决方案5】:

          你可以试试INSTR:

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

          我无法访问 Oracle 来测试并确定它是否比使用通配符的 LIKE 更快。

          【讨论】:

            【解决方案6】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-06-08
              • 1970-01-01
              • 2018-11-26
              • 2016-07-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多