sql查询中函数执行的顺序是什么?

时间:2018-09-26 17:06:13

标签: sql oracle

如果我构建自己的函数“ myfunction”并执行以下查询:

select
myfunction(parameters)
from
mytable
where
a and b and c and d

如果mytable有100万行,但是在我的位置之后我只有100行。 当我执行此查询时,myfunction将执行100或100万行吗?

在这种情况下会发生什么?

select
myfunction(parameters)
from
mytable
where
a and b and c and d and myfunction(parameters) == e

4 个答案:

答案 0 :(得分:1)

在SQL中,执行顺序实际上并没有任何意义,特别是在Oracle等复杂数据库中。实际运行的是有向无环图,它表示诸如“嵌套循环”和“索引范围扫描”之类的运算符。这些是您不会直接在SQL语句中看到的运算符。

因此,您需要为该函数被调用100次或1,000,000次做准备。而且,在不同情况下,Oracle可以选择其中一个。

对于where子句,最好不要重复该函数调用。在Oracle 12C中,我将使用横向联接。在早期版本中,CTE或子查询应表明where并未调用该函数。

答案 1 :(得分:1)

在第一个示例中,它将仅执行100次。您可以通过在函数中添加调试调用来验证这一点:

create table mytable (a, b) as select mod(level, 10), level from dual connect by level <= 50;

create or replace function myfunction(p number)
return number as
begin
  dbms_output.put_line('In function for p=' || p);
  return mod(p,3);
end;
/

set serveroutput on

select myfunction(b)
from mytable
where a = 1;

MYFUNCTION(B)
-------------
            1
            2
            0
            1
            2

In function for p=1
In function for p=11
In function for p=21
In function for p=31
In function for p=41

仅针对与where子句过滤器匹配的行调用该函数。但是,据我所知,这不能保证。

在第二个示例中它要复杂得多,并且在很大程度上取决于优化程序。在我的简单演示中,优化器(在本例中为11gR2)首先评估a,并且仅调用与之匹配的行的函数;但随后会再次调用它作为选择列表值:

select myfunction(b)
from mytable
where a = 1
and myfunction(b) = 2;

MYFUNCTION(B)
-------------
            2
            2

In function for p=1
In function for p=11
In function for p=11
In function for p=21
In function for p=31
In function for p=41
In function for p=41

对于之前a=1的五行中的每一行都调用该函数,对于myfunction(b) = 2的第五行则再次调用该函数,以获取结果集中的值。

同样,在此示例中,您可能认为不会改变这种行为的事情。所有这些都获得完全相同的输出:

select myfunction(b)
from mytable
where myfunction(b) = 2
and a = 1;

select x
from (
  select myfunction(b) as x
  from mytable
  where a = 1
)
where x = 2;

select x
from (
  select /*+ materialize */ myfunction(b) as x
  from mytable
  where a = 1
)
where x = 2;

with t (x) as (
  select myfunction(b)
  from mytable
  where a = 1
)
select x
from t
where x = 2;

优化器在内部将它们全部重写为同一查询,您仍然会获得全部七个函数调用。添加未记录的提示会更改它:

with t (x) as (
  select /*+ materialize */ myfunction(b)
  from mytable
  where a = 1
)
select x
from t
where x = 2;

         X
----------
         2
         2

In function for p=1
In function for p=11
In function for p=21
In function for p=31
In function for p=41

但是您不能(或不应)真正使用或依赖它。

索引,分区,优化器版本,统计信息等都将影响优化器对您的查询的行为。

还有其他需要考虑的事情,您可以使用基于函数的索引或确定性函数...

所以...这取决于。

答案 2 :(得分:1)

SQL没有执行顺序。是一种声明性语言。最终,唯一正确的“命令”是实际执行计划中描述的命令。请参见Displaying Execution Plans by Using SQL Server Profiler Event Classes和显示图形执行计划(SQL Server Management Studio)。

一个完全不同的事情是查询,子查询和表达式如何将自身投影为“有效性”。例如,如果在SELECT投影列表中具有别名表达式,则可以在WHERE子句中使用别名吗?像这样:

SELECT col1+col2 as col3

从t WHERE col3 = ...;

了解执行SQL查询的顺序可以极大地帮助我们优化查询。对于大型和复杂的查询尤其如此,知道执行顺序可以使我们免于不必要的结果,并帮助我们创建执行速度更快的查询。

SEE The Execution oF Where,ON,Group By

请避免在where子句中使用函数,将对表中的每个记录进行检查。

答案 3 :(得分:1)

在第二个查询 Where 子句中,该子句将始终执行1,000,000次,但是如果先前的条件在优化器中放弃了它的执行,例如在下面的示例 myfunction 完全不会执行。

select *
from mytable
where a and b and c and d and 1=0 and myfunction(parameters) == e

之所以会发生此行为,是因为优化程序检测到已达到“假”条件,因此无需执行任何个其他条件。

---第一个查询---

select myfunction(parameters)
from mytable
where a and b and c and d

我的功能 将在您的where子句之后执行 ,因此,如果您查询仅返回100条记录,它将执行100次。 / p>

---第二个查询---

select myfunction(parameters)
from mytable
where a and b and c and d and myfunction(parameters) == e

第一个 功能 将在您的 select 子句以及您的 where 子句中执行两次,因此,如果您的查询仅返回100条记录,它将被执行100次。但第二次 myfuntion 调用将被执行 一百万次

避免在甲骨文中执行 一百万 函数的最佳方法是MATERIALIZE提示和 WITH < / strong>查询,以下查询应返回与第二个查询相同的结果:

with hundred_records as (
    select /*+ MATERIALIZE */ myfunction(parameters) fn_result, mytable.*
    from mytable
    where a and b and c and d
)
select *
from mytable
where fn_result = e

但是,我强烈建议您在 mytable 内添加一列,以在其中存储 myfunction 结果,这样您将为自己节省很多性能问题。每当您知道“参数” 已更改时,都必须更新该列。