如果我构建自己的函数“ 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
答案 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 结果,这样您将为自己节省很多性能问题。每当您知道“参数” 已更改时,都必须更新该列。