Postgresql函数卡在for循环中
该函数在循环之前被卡住.
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) 我想问题必须是桌子的锁定.但我绝对不明白是什么原因以及可以解决的问题. 前段时间评论部分正在运作.但过了一会儿,出现了同样的问题.我通过更改查询并用内部联接替换条件(级联查询)来解决它.但这次他们都没有工作! 更新 我通过一个愚蠢的改变再次使它工作: 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没有关于数据的准确信息,则必然会做出糟糕的决定.对所涉及的表进行分析可能有所帮助,但通常不需要这样做 – autovacuum通常应该使统计数据保持最新(假设您已运行). 统计偏差的一个常见原因是值的分布不均匀(在您的情况下,如果每个连接的数据包数量有很大差异).通过使用 如果没有其他工作,您可以通过EXECUTE运行查询来绕过计划缓存. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |