函数卡在循环之前。
select * from scm_main.fn_connection_stations(1219646)
打印消息“开始...”但不会打印消息“...结束”。
CREATE OR REPLACE FUNCTION
scm_main.fn_connection_stations(var_connection_id bigint)
RETURNS SETOF scm_main.typ_connection_stations AS
$BODY$ DECLARE
var_affected INTEGER DEFAULT 0;
var_row scm_main.typ_connection_stations%ROWTYPE;
BEGIN
RAISE NOTICE 'Start...';
FOR var_row IN
SELECT DISTINCT v.vbvdata_station_id
FROM scm_main.tbl_vbvdata AS v
INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id =
p.packet_id and p.packet_connection_id = var_connection_id)
--WHERE v.vbvdata_packet_id IN
--( SELECT packet_id FROM scm_main.tbl_packet AS o_p WHERE
o_p.packet_connection_id = var_connection_id)
LOOP
RETURN NEXT var_row;
END LOOP;
RAISE NOTICE '...End';
RETURN;
END
$BODY$
LANGUAGE plpgsql STABLE STRICT
COST 100
ROWS 1000;
ALTER FUNCTION scm_main.fn_connection_stations(bigint)
OWNER TO postgres;
查询本身非常简单,像这样直接调用时运行:
SELECT DISTINCT v.vbvdata_station_id
FROM scm_main.tbl_vbvdata AS v
INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id =
p.packet_id and p.packet_connection_id = 1219646)
我想问题一定是表的lockibg。但我完全不明白是什么原因以及有什么解决办法。
前段时间评论的部分是有效的。但是过了一段时间又出现了同样的问题。我通过更改查询并将条件(级联查询)替换为内部连接来解决它。但是这次它们都不起作用!
已更新
我做了一个愚蠢的改变让它再次工作:
INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id = p.packet_id
and p.packet_connection_id = var_connection_id)`
更改为:
INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id = p.packet_id)
where p.packet_connection_id in (select var_connection_id)
并且工作完美。
另一个有趣的地方是,即使是下面的更改也不起作用并且仍然挂起:
INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id = p.packet_id)
where p.packet_connection_id = var_connection_id
现在我找到了解决办法。但我想知道这是怎么发生的!
最佳答案
如果它是通过对查询进行如此肤浅的更改来修复的,那么它可能不是“卡住”,而是由于执行计划选择不当而导致运行非常缓慢。
事实上,查询在函数中的表现比它自己的表现更差,这可能是 plan caching 的结果。 .基本上,Postgres 可能会尝试通过创建和重用通用(即参数无关)执行计划来避免重新计划查询的成本。不幸的是,这些通用计划可能远非最佳。
糟糕计划的一个可能解释是糟糕的统计数据;如果 Postgres 没有关于数据的准确信息,它必然会做出错误的决定。对所涉及的表进行 ANALYSE
可能会有所帮助,但这通常不是必需的 - autovacuum 通常应该使统计信息保持最新状态(假设您正在运行它)。
统计数据偏斜的一个常见原因是值分布不均匀(在您的情况下,如果每个连接的数据包数量有很大差异)。这可能会通过使用 ALTER TABLE ... SET STATISTICS
增加统计信息的详细程度而得到很大改善。 (后跟 ANALYSE
)。在某些情况下,高值会减慢规划速度,但 500(可能)是一个安全的起点。
如果其他方法都不起作用,您始终可以通过 EXECUTE
运行查询来绕过计划缓存。
关于Postgresql 函数卡在 for 循环中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30298299/