Oracle SQL:如果我将一个函数既作为字段又按顺序使用,是否会再次进行评估?

时间:2015-04-09 10:45:17

标签: sql oracle performance plsql oracle11g

假设您有一个PL/SQL函数,它返回一些随机值,您将在SQL sentence中使用它作为返回数据和Order by子句。

现在你可以在三个"不同的"中编写Order by条款。方法:

按索引

Select Foo,
       MyFunction(Foo) orderField
  From FooTable
 Order By 2

再次呼叫""功能

Select Foo,
       MyFunction(Foo) orderField
  From FooTable
 Order By MyFunction(Foo)

使用订单字段别名

Select Foo,
       MyFunction(Foo) orderField
  From FooTable
 Order By orderField

第三种方式是可能的,因为Order By子句是要解析的select的最后一个,然后Oracle已经知道了别名。

我的问题是,这三个查询的处理或性能有什么不同吗?特别是,第二个意味着是否会再次评估MyFunction来电?

我试图通过搜索文档,并运行来自 Toad 的一些查询以及查看explain plan来查找,但直到现在才发现任何重大差异。

我的Oracle版本是11.2.0.3.0,如果这有任何影响。

2 个答案:

答案 0 :(得分:7)

在这种情况下检查发生了什么的好方法是使用序列(但我有oracle版本12.1)。例如:

SQL> create sequence func_seq;

Sequence created.

SQL> create or replace function foo return number is
begin
  return func_seq.nextval;
end;
/

Function created.

首先,创建一个返回两行(没有ORDER BY子句)的查询并检查序列的值:

SQL> select foo from dual connect by level <= 2;

       FOO
----------
         1
         2

SQL> select func_seq.currval from dual;

   CURRVAL
----------
         2

然后使用ORDER BY的查询:

SQL> select foo from dual connect by level <= 2 order by foo;

       FOO
----------
         3
         4

SQL> select func_seq.currval from dual;

   CURRVAL
----------
         4

在这两种情况下,功能被执行了2次 但是如果你的函数需要参数,你必须注意它们的值:

SQL> create or replace function foo(p number) return number is
begin
  return func_seq.nextval;
end;
/  

Function created.

使用不同的参数进行查询:

SQL> select foo(1) from dual connect by level <= 2 order by foo(2);

    FOO(1)
----------
         6
         8

SQL> select func_seq.currval from dual;

   CURRVAL
----------
         8

正如我们所见,功能被执行了4次。

答案 1 :(得分:2)

在您的情况下,函数仅评估一次,ORDER BY子句中的表达式仅用作对SELECT子句中列的引用。 当表达式不匹配时,函数将被评估两次,例如

Select Foo,
       MyFunction(Foo) orderField
From FooTable
Order By MyFunction(Foo)*2

我希望Oracle缓存确定性函数的结果(必须在函数定义中明确说明),因此在这种情况下,重用缓存结果。