我有一个简单的函数,如果我运行它,大约需要40秒才能完成。
select * from f_cyklus1(100000000)
但是如果我在8个分离的实例中运行这个函数8次,这意味着所有的8个函数都是并行运行的,每个实例都需要210到260秒才能完成。这是一个大幅度下降的表现。我试着把它编译成8个单独的函数,然后再运行一次,但是性能没有变化。
select * from f_cyklus1(100000000);
select * from f_cyklus2(100000000);
select * from f_cyklus3(100000000);
select * from f_cyklus4(100000000);
select * from f_cyklus5(100000000);
select * from f_cyklus6(100000000);
select * from f_cyklus7(100000000);
select * from f_cyklus8(100000000);
那么为什么要花40多岁,而不是210-260年才能完成呢?我们的虚拟机有16个CPU,物理硬件使用率很低。在测试时,我也是唯一使用Postgre数据库的人。
create or replace function f_cyklus1 (p_rozsah int) returns bigint as -- drop function f_cyklus(int)
$body$
declare
declare
v_exc_context TEXT;
v_result INTEGER;
p_soucet bigint :=0;
begin
for i in 0..p_rozsah
loop
p_soucet = p_soucet + i;
end loop;
return p_soucet;
EXCEPTION
WHEN OTHERS THEN
GET STACKED DIAGNOSTICS v_exc_context = PG_EXCEPTION_CONTEXT;
PERFORM main.ut_log('ERR', SQLERRM || ' [SQL State: ' || SQLSTATE || '] Context: ' || v_exc_context );
RAISE;
END;
$body$ LANGUAGE plpgsql
PostgreSQL 11.6 on x86_64-pc-linux-gnu,由gcc (GCC) 4.8.5 20150623 (RedHat4.8.5-39),64位编译
虚拟机: Centos 7+ KVM
HW: 2x AMD EPYC 7351 + 256 GB RAM
注意:我已经问过类似的问题,我认为这是由于异步处理,但这表明问题实际上是在原始Postgres性能,因此我删除了我的前一个问题,并问了这个新的问题。
发布于 2020-01-22 08:53:55
p_soucet = p_soucet + i;
每次这样做,它都必须获得一个运行语句的“快照”,因为它在幕后使用常规SQL引擎,并且总是需要在快照中运行。获取快照需要系统范围内的锁定。同时运行的进程越多,它们花更多的时间来获取快照,而不是做有用的工作。
如果您在设置为“可重复读取”的事务中运行该函数,您会发现它们的扩展性更好,因为它们在持续时间内保持相同的快照,并保持重复使用它。当然,这可能会干扰您的实际用例。
plpgsql实际上并不适合于这类工作,只需进行扩展。您可以使用其他pl语言之一,如plperl或plpythonu。
在https://www.postgresql.org/docs/current/plpgsql-expressions.html中描述了主SQL引擎如何计算表达式。
快照通常从https://www.postgresql.org/docs/current/mvcc.html开始在文档中进行讨论。
我不知道这两者之间的交互被记录在任何地方,供最终用户使用。
https://stackoverflow.com/questions/59846912
复制