Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
postgresql中的select function()对函数()调用过多_Sql_Postgresql_Stored Procedures_Plpgsql - Fatal编程技术网

postgresql中的select function()对函数()调用过多

postgresql中的select function()对函数()调用过多,sql,postgresql,stored-procedures,plpgsql,Sql,Postgresql,Stored Procedures,Plpgsql,假设我们有这个函数: create or replace function foo(a integer) returns table (b integer, c integer) language plpgsql as $$ begin raise notice 'foo()'; return query select a*2, a*4; return query select a*6, a*8; return query select a*10, a*12; e

假设我们有这个函数:

create or replace function foo(a integer)
returns table (b integer, c integer)
language plpgsql
as $$
begin
    raise notice 'foo()';
    return query select a*2, a*4;
    return query select a*6, a*8;
    return query select a*10, a*12;
end;
$$;
“raisenotice'foo()”部分将用于了解调用函数的次数

如果我这样调用函数:

postgres=# SELECT i, foo(i) as bla FROM generate_series(1,3) as i;
NOTICE:  foo()
NOTICE:  foo()
NOTICE:  foo()
 i |   bla   
---+---------
 1 | (2,4)
 1 | (6,8)
 1 | (10,12)
 2 | (4,8)
 2 | (12,16)
 2 | (20,24)
 3 | (6,12)
 3 | (18,24)
 3 | (30,36)
(9 rows)
我们可以看到,正如预期的那样,foo()被调用了3次

但是如果我以这种方式调用该函数(因此我实际上在不同的列中得到foo()结果):

我们可以看到foo()被调用了6次。如果foo()返回3列,它将被调用9次。很明显,foo()是为每个i和它返回的每个列调用的

我不明白为什么博士后不在这里进行优化。这对我来说是个问题,因为我的(真实的)foo()可能是CPU密集型的。有什么想法吗

编辑: 使用“不可变”函数或不返回多行的函数会产生相同的行为:

create or replace function foo(a integer)
returns table (b integer, c integer, d integer)
language plpgsql
immutable
as $$
begin
raise notice 'foo';
return query select a*2, a*3, a*4;
end;
$$;

postgres=# select i, (foo(i)).* from generate_series(1,2) as i;
NOTICE:  foo
NOTICE:  foo
NOTICE:  foo
NOTICE:  foo
NOTICE:  foo
NOTICE:  foo
 i | b | c | d 
---+---+---+---
 1 | 2 | 3 | 4
 2 | 4 | 6 | 8
(2 rows)

基本上,在
select
子句中不调用返回多个值的函数(尤其是返回集合的函数)是合理的。 事实上,postgres并没有对这样的调用进行任何优化。 将函数放在
from
子句中

SELECT i, f.* FROM generate_series(1,3) as i, foo(i) f;
在中,您可以找到注释(强调我的):

目前,还可以在select中调用返回集合的函数 查询的列表。对于查询本身生成的每一行 调用函数返回集,并为其生成输出行 函数结果集的每个元素。然而,请注意,这 该功能已弃用,可能会在将来的版本中删除


基本上,在
select
子句中不调用返回多个值的函数(尤其是返回集合的函数)是合理的。 事实上,postgres并没有对这样的调用进行任何优化。 将函数放在
from
子句中

SELECT i, f.* FROM generate_series(1,3) as i, foo(i) f;
在中,您可以找到注释(强调我的):

目前,还可以在select中调用返回集合的函数 查询的列表。对于查询本身生成的每一行 调用函数返回集,并为其生成输出行 函数结果集的每个元素。然而,请注意,这 该功能已弃用,可能会在将来的版本中删除

这是一个众所周知的问题

SELECT (f(x)).*
宏在解析时是否扩展为

SELECT (f(x)).a, (f(x)).b, ...
PostgreSQL不会将对同一函数的多个调用合并为一个调用

为了避免此问题,您可以将其包装在另一层子查询中,以便宏扩展发生在对函数结果的简单引用上,而不是函数调用上:

select i, (f).* 
FROM (
    SELECT i, foo(i) f from generate_series(1,2) as i
) x(i, f)
或者在
FROM
子句中使用横向调用,这是较新版本的首选:

select i, f.*
from generate_series(1,2) as i
    CROSS JOIN LATERAL foo(i) f;
使用传统的逗号连接和隐式的横向连接,
交叉连接横向连接可以省略,但是我发现包含它非常明显,特别是当您混合其他连接类型时。

这是一个已知的问题

SELECT (f(x)).*
宏在解析时是否扩展为

SELECT (f(x)).a, (f(x)).b, ...
PostgreSQL不会将对同一函数的多个调用合并为一个调用

为了避免此问题,您可以将其包装在另一层子查询中,以便宏扩展发生在对函数结果的简单引用上,而不是函数调用上:

select i, (f).* 
FROM (
    SELECT i, foo(i) f from generate_series(1,2) as i
) x(i, f)
或者在
FROM
子句中使用横向调用,这是较新版本的首选:

select i, f.*
from generate_series(1,2) as i
    CROSS JOIN LATERAL foo(i) f;

使用传统的逗号连接和隐式的横向连接,
交叉连接横向连接
可能会被省略,但我发现包含它相当明显,特别是当您混合其他连接类型时。

select
子句中调用函数是完全合理的-但是调用返回集合的函数是不合理的(=多行)在
select
条款中,该函数不返回集合,而是返回一行。在
select
中调用集合返回函数时会出现不同的问题,
LATERAL
仍然是首选。@klin Er.是的。我请求-enocafee。多个调用的问题不是由它返回集合来调用的,而是返回集合。这是tot调用
select
子句中的函数是合理的,但调用返回集合(=多行)的函数是不合理的在
select
clause中,该函数不返回集合,而是返回一行。在
select
中调用集合返回函数时,会出现不同的问题,
LATERAL
仍然是首选。@klin Er.是的。我请求-enocafee。多个调用的问题不是由它返回集合来调用的,而是返回集合。这是什么“x(i,f)”?它只是一个花哨的别名还是别的什么?如果我用一个随机字符串替换它,请求仍然有效。@user368507是的,它指定子查询返回的表和列。表名部分是必需的。如果省略,列默认为内部查询的列名。“x(i,f)”是什么“?它只是一个花哨的别名还是别的什么?如果我用随机字符串替换它,请求仍然有效。@user368507是的,它指定子查询返回的表和列。表名部分是必需的。如果省略,则默认为内部查询的列名。”。