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

sql查询中函数的执行顺序是什么?,sql,oracle,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 m

如果我构建自己的函数“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

一般来说,执行顺序在SQL中并不意味着什么,尤其是在Oracle这样的复杂数据库中。实际运行的是一个有向无环图,它表示诸如“嵌套循环”和“索引范围扫描”之类的运算符。这些是您在SQL语句中无法直接看到的运算符

因此,您需要为调用该函数100次或1000000次做好准备。而且,在不同的情况下,甲骨文可能会选择其中之一


对于
where
子句,最好不要重复函数调用。在Oracle 12C中,我将使用横向联接。在早期版本中,CTE或子查询应该传达这样一个信息,即对于
(其中
)(在第一个示例中,它将只执行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
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;
Optimizer在内部将它们全部重写到同一个查询中,您仍然可以得到所有七个函数调用。添加未记录的提示会改变它:

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
但你不能(或不应该)真正使用或依赖它

索引、分区、Optimizer版本、统计信息等都会影响Optimizer在查询中的行为

和其他需要考虑的一样,你可以有一个基于函数的索引,或者一个确定性函数…


所以。。。这取决于具体情况。

SQL没有执行顺序。是一种声明性语言。最终,唯一正确的“顺序”是实际执行计划中描述的顺序。请参阅并显示图形执行计划(SQL Server Management Studio)

但另一件完全不同的事情是,查询、子查询和表达式如何将自己投射到“有效性”中。例如,如果在“选择投影”列表中有一个别名表达式,可以在WHERE子句中使用别名吗?像这样:

SELECT col1+col2 as col3
从t 其中col3=

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


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

在第二次查询中,where子句将始终执行1000000次,但是如果以前的条件在优化器中放弃执行,则可以跳过它,例如,在下面的示例中,myfunction根本不会执行

select *
from mytable
where a and b and c and d and 1=0 and myfunction(parameters) == e
出现这种行为是因为优化器检测到已达到“false”条件,因此无需执行任何其他条件

--第一次查询--

select myfunction(parameters)
from mytable
where a and b and c and d
select myfunction(parameters)
from mytable
where a and b and c and d and myfunction(parameters) == e
myfunction将在您的where子句之后执行,因此如果查询只返回100条记录,它将执行100次

——第二次查询--

select myfunction(parameters)
from mytable
where a and b and c and d
select myfunction(parameters)
from mytable
where a and b and c and d and myfunction(parameters) == e
首先,myfunction将执行两次,一次在您的select子句中执行,另一次在您的where子句中执行,因此如果查询只返回100条记录,它将执行100次。但是对于你的第二次MyFunction调用,它将执行100万次

避免在oracle中执行100万函数的最佳方法是使用查询的提示和,以下查询应返回与第二个查询相同的结果:

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结果,这样做可以避免很多性能问题。每次您知道“参数”
发生更改时,您都必须更新该列。

如果我只想对100行执行该函数,那么我应该首先运行主查询,然后将该函数应用于结果吗?使用select myfunction from(select…)或with子句?是。如果可以避免的话,不要把它放在WHERE子句中。SELECT子句中的函数对于查询返回的每一行只运行一次。WHERE子句中的函数可以为表中的每一行运行一次。当然,对于给定的示例,您可以通过在SELECT子句中选择2而不是myfunction(参数),避免在每一行上重复执行函数!由于WHERE子句保证所有选定行的函数值都为2,因此没有理由在SELECT中使用函数而不是常量值。对于第一个示例,我相信可以保证函数只针对输出中包含的行进行计算。这应该由子句的求值顺序来“保证”-SELECT表达式仅在计算了其他子句(order by除外)之后才进行计算,并且仅针对进入输出的行进行计算。它不能是任何其他方式-选择可能包括聚合函数或分析函数-所有这些都首先取决于输出中的行。(当然,Oracle和SQL标准所保证的并不总是有保证的…-)是的,没错。我在不同的地方看到了评估顺序的描述和陈述,但在官方文件中没有。所以我