繁体   English   中英

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

[英]What is the order of execution of a function in an sql query?

如果我构建自己的函数“ 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次或1,000,000次做准备。 而且,在不同情况下,Oracle可以选择其中一个。

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

在第一个示例中,它将仅执行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 ,将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

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

索引,分区,优化器版本,统计资料等,均会影响优化器的行为进行查询

和其他需要考虑的事情一样,您可以具有基于函数的索引或确定性函数...

所以...这取决于。

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

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

SELECT col1+col2 as col3

从t WHERE col3 = ...;

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

查看执行方式,按位置分组

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

在您的第二个查询中, 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

myfunction where子句之后执行,因此如果您的查询仅返回100条记录,它将执行100次。

-第二查询-

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

第一个myfunction将在select子句和where子句中执行两次,因此,如果查询仅返回100条记录,它将执行100次。 但是对于您的第二次myfuntion呼叫,它将被执行100万次

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

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结果存储在其中,这样您将为自己节省很多性能问题。 每当您知道“参数”已更改时,都必须更新该列。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM