Postgresql 函数卡在 for 循环中

标签 postgresql loops for-loop locking

函数卡在循环之前。

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/

相关文章:

php - PHP的 Assets 错误回显其他

java - 如何在java中创建一个每次迭代返回不同变量的循环?

c - 如果没有 printf,For 循环将无法工作

java - 计算最后一列素数

postgresql - 如何在 PostgreSQL 的函数中使用\COPY 命令

sql - 使用 PostgreSQL 在一个语句中重命名多个列

javascript - Ruby - 数组检查并替换为

Java For循环三角形图案

sql - 从许多表中清除内容的最快方法

ruby-on-rails - 尝试在本地访问我的应用程序时,我得到 : "could not translate host name ... to address" and "Temporary failure in name resolution"