不使用索引访问时的基于函数的索引

时间:2012-07-24 09:34:23

标签: oracle indexing user-defined-functions

我第一次使用基于函数的索引和用户定义的函数,并且在索引无法使用时遇到了性能问题。

在内部,基于函数的索引似乎生成一个隐藏的表列(类型为varchar2(4000),因为我的函数返回一个varchar2),并对其进行索引。使用索引时工作正常,但有时我们必须使用函数作为过滤器进行全表扫描,在这种情况下,我看到性能下降了6倍。在这种情况下,Oracle不使用隐藏列,但重新计算每一行的函数,使查询受CPU限制而不是IO绑定。

有没有办法让Oracle使用该隐藏列进行过滤?我想知道我是否错过了一些重写选项或类似的东西。

如果没有,我必须自己定义列并使用触发器使其保持最新。我更倾向于使用基于函数的索引来实现透明度和更简单的维护。

2 个答案:

答案 0 :(得分:3)

您使用的是哪个版本的Oracle?如果是11克,你应该尝试using a virtual column。这是一个列,其值来自表达式或文字。它们被定义为表的一部分,因此它们在表DESC中具有可见性(与基于函数的索引不同)。我们可以在虚拟列上构建索引。并且它们会自动维护,无需触发器。

因此,您可以使用与基于函数的索引相同的表达式向表中添加虚拟列。也许是这样的:

create table t23
   (id number
    , col_a varchar2(10)
    , vcol_a as (upper(substr(col_a, 1, 1)))
  )
/

请注意,我们无法插入或更新虚拟列。所以你需要指定insert语句的投影:

insert into t23 (id, col_a) values (1, 'this is a test');

然后,您可以在虚拟列上构建常规索引:

create index t23_vc_i on t23(vcol_a)
/

不要忘记删除基于函数的索引!

答案 1 :(得分:0)

没有通用的方法可以在表扫描中使用基于函数的索引。

我在我的问题中做出的假设,即“在内部,基于函数的索引似乎生成一个隐藏的表列......”,是完全错误的:函数的结果是< em> not 存储在表列中,但仅存储在索引中。

因此,除非在执行扫描时有一种方法可以访问索引(我能想到的唯一方法是它是一个以键列开头的组合索引),预计算的函数结果不能是使用

11g“虚拟列”功能也没有帮助,因为列没有存储在表中,而是在运行中计算,类似于在视图中使用该功能。

总结:如果您不能排除表扫描,并且您的函数调用很昂贵(慢),请使用实列与“插入或更新前”触发器结合使用。基于函数的索引不会这样做。

(注意:添加了这个答案,因为我不想让这个问题没有答案。答案归功于thilo,他指出该列永远不会实现。)