一起执行多个功能而不会降低性能

fra*_*ima 10 postgresql plpgsql database-performance query-performance postgresql-performance

我有这个过程,必须使用pl/pgsql进行一系列查询:

--process:
SELECT function1();
SELECT function2();
SELECT function3();
SELECT function4();
Run Code Online (Sandbox Code Playgroud)

为了能够在一次调用中执行所有操作,我创建了一个过程函数:

CREATE OR REPLACE FUNCTION process()
  RETURNS text AS
$BODY$
BEGIN
    PERFORM function1();
    PERFORM function2();
    PERFORM function3();
    PERFORM function4();
    RETURN 'process ended';
END;
$BODY$
  LANGUAGE plpgsql
Run Code Online (Sandbox Code Playgroud)

问题是,当我总结每个函数自身所用的时间时,总计为200秒,而函数所process()用的时间超过一个小时!

也许这是一个内存问题,但我不知道postgresql.conf应该改变哪种配置.

DB在Debian 8中的PostgreSQL 9.4上运行.

Erw*_*ter 10

您评论说4个函数必须连续运行.因此,可以安全地假设每个函数都使用上一个函数修改过的表中的数据.那是我的主要嫌疑人.

任何Postgres函数都在外部上下文的事务中运行.因此,如果打包到另一个函数中,所有函数共享相同的事务上下 显然,每个人都可以看到对以前功能的数据的影响.(即使效果对其他并发事务仍然是不可见的.)但统计信息不会立即更新.

查询计划基于所涉及对象的统计信息.PL/pgSQL在实际执行之前不会计划语句,这对您有利.每个文件:

当每个表达式和SQL命令首先在函数中执行时,PL/pgSQL解释器使用SPI管理器的SPI_prepare函数解析并分析命令以创建预准备语句.

PL/pgSQL 可以缓存查询计划,但只能在同一个会话中(至少在第9.2+页中),只有在几次执行后才能显示相同的查询计划才能重复运行.如果您怀疑这对您来说是错误的,您可以使用动态SQL来解决它,每次都会强制执行一个新计划:

EXECUTE 'SELECT function1()';
Run Code Online (Sandbox Code Playgroud)

但是,我看到的最可能的候选者是导致查询计划较差的无效统计信息.函数内部的SELECT/ PERFORMstatements(同样的东西)快速连续运行,autovacuum没有机会在一个函数和下一个函数之间启动和更新统计信息.如果一个函数实质上改变了下一个函数正在使用的表中的数据,则下一个函数可能将其查询计划基于过时的信息.典型示例:具有几行的表格中填充了数千行,但下一个计划仍然认为"小"表的顺序扫描速度最快.你说:

当我总结每个函数自身所用的时间时,总计是200秒,而函数process()所花费的时间超过一个小时!

什么确切地不"本身"是什么意思?您是在一次交易或个别交易中运行它们吗?甚至可能介于两者之间?这将允许autovacuum更新统计信息(通常相当快),并可能根据更改的统计信息导致完全不同的查询计划.

您可以使用auto-explain检查plpgsql函数内的查询计划

如果您能识别出这样的问题,可以ANALYZE在语句之间强制执行.在它,只有几个SELECT/ PERFORM语句你也可以使用更简单的SQL函数,并完全避免计划缓存(但见下文!):

CREATE OR REPLACE FUNCTION process()
  RETURNS text AS
$func$
   SELECT function1();

   ANALYZE some_substantially_affected_table;

   SELECT function2();
   SELECT function3();

   ANALYZE some_other_table;

   SELECT function4();
   SELECT 'process ended';  -- only last result is returned
$func$  LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)

此外,只要我们没有看到被调用函数的实际代码,就可以有任意数量的其他隐藏效果.
示例:您可以使用SET LOCAL ...一些配置参数来提高您的性能function1().如果在不影响其余事务的单独事务中调用.效果只持续到交易结束.但如果在一次交易中调用它也会影响其余的事务......

基本:

另外:事务累积锁定,这会锁定越来越多的资源,并可能导致与并发进程的摩擦增加.所有锁都在事务结束时释放.如果可能的话,最好在单独的事务中运行大函数,而不是包装在单个函数中(因此包含事务).最后一项与@klinIMSoP已涵盖的内容有关.

  • 致@Erwin。不,我的意思是[这个](http://www.postgresql.org/message-id/E1XjbTw-0002f9-Ri@gemulon.postgresql.org)。 (2认同)