1

我需要一些关于 postgres 中 plpgsql 函数的帮助。这个问题已在 psql-general 上提出,但没有确定的答案(此处此处

这归结为:

如何创建一个 plpgsql 函数,其中一组行作为输入,一组行作为输出,而不使用数组(为了性能)。

我目前将输入作为游标的引用传输,但它并不令人满意,因为它强制计算两次相同的查询 ( SELECT ...hard_work...) 并且它在我的应用程序中弄乱了事务。

目前它的工作方式如下:

DECLARE cursor FOR ...hardwork...;

WITH first_query AS (
SELECT ...hard_work... --second computation of hard_work
   ),
second_query AS ( 
    SELECT ...another_query_using_hard_work...
   )
SELECT *
FROM my_function('cursor'::refcursor) f(...) ;

最终我想有类似的东西(不工作)

WITH first_query AS ( 
    SELECT ...hard_work...
   ),
second_query AS ( 
    SELECT ...another_query_using_the_hard_work_query...
   )
SELECT *
FROM my_function('first_query'::regclass) f(...) ;

当然 SELECT ...hard_work... 很昂贵(大约 50 毫秒),最好不要计算两次。应用是数据流,所以时间很宝贵,数据很重,所以在临时表中复制数据可能比计算两次(通常是几十MB)还要糟糕。

提出了其他解决方案

  • 传输视图或表引用作为输入,这与使用游标的问题相同(即:计算的两倍,单独的语句)

  • 传输/输出数组:使用 array_agg() 和 unnest() 强制进行大量计算

  • 传输临时表:涉及复制数据:它可能比计算两次要长(我正在争取 50 毫秒)

  • 传输物化视图:仅在 9.3 中可用

我将非常感激能对这个主题有深入的了解。

此致,

雷米-C

PS:psql-general邮件列表上的问题链接包含很多关于特定甚至所有代码的详细信息。

PPS:版本:postgres 9.2。操作系统:Ubuntu 12.04 LTE,客户端:PGAdmin3 用于测试,node.js 用于生产。

4

2 回答 2

1

据我所知,您还没有尝试使用临时表

您可以使用硬编码名称甚至使用动态名称来执行此操作,可能使用 aSEQUENCE来获取唯一的表名称。然后,您将在 PL/pgSQL 函数中使用动态 SQL,EXECUTE并将表名(或者更好:对象标识符 type regclass)传递给它。

确保ANALYZE在重大更改之后(通常在最初填充它之后)立即在更大的临时表上手动运行,因为临时表对 autovacuum 守护进程不可见。
甚至可能在大型临时表上创建索引!

您可以在 Stackoverflow 上找到许多代码示例。一个特别丰富和松散相关的答案:
重构一个 PL/pgSQL 函数以返回各种 SELECT 查询的输出

于 2013-09-18T14:00:09.330 回答
0

我认为解决此类问题的典型方法是使用自定义聚合/函数。然后你可以使用任何你想要的内部存储。每一行都直接传入、转换,然后再进行处理。

于 2013-11-16T11:06:35.877 回答