Oracle SQL:如果我将一个函数同时用作字段和排序依据,它是否会再次求值?

Oracle SQL: If I use a function both as a field and in order by, is it evaluated again?

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

现在您可以用三种 "different" 方式编写 Order by 子句:

按索引

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

通过调用"again"函数

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,如果有任何问题的话。

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

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

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

在这种情况下检查发生了什么的一个好方法是使用序列(但我有 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.

首先,查询 return 两行(没有 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 次。