2013-04-29 76 views
2

我正在使用PL/pgSQL函数“interpolate_values”进行一些耗时的计算。所谓“interpolation_jobs” A表包含有关每个函数调用监控信息,例如通过在PL/pgSQL函数中立即更新

SELECT status FROM interpolation_jobs WHERE id = job_id; 

列“状态”中包含的一个值与给定的job_id函数调用的进程应该是可观察的“排队” ,'跑步'或'完成'。

CREATE OR REPLACE FUNCTION interpolate_values (job_id INTEGER) 
RETURNS VOID 
LANGUAGE plpgsql VOLATILE 
AS $$ 
DECLARE 
BEGIN 
    EXECUTE 'UPDATE interpolation_jobs 
     SET status = ''running'', progress = 0.0 
     WHERE id = ' || job_id || ';'; 

-- 
-- ... some extensive database computations ... 
-- 

    EXECUTE 'UPDATE interpolation_jobs 
     SET status = ''done'' 
     WHERE id = ' || job_id || ';'; 

END; 
$$; 

的状态不是函数期间更新我的问题是:在功能开始时,状态从“排队”到“运行”,在年底将其设置为“完成”改变呼叫。实际更新发生在函数调用返回时。所以,状态从“排队”直接变为“完成”。行

EXECUTE 'UPDATE interpolation_jobs 
     SET status = ''running'', progress = 0.0 
     WHERE id = ' || job_id || ';'; 

没有效果。

是否有可能立即更新PL/pgSQL中的值,以便在函数调用返回之前可以访问新值?

谢谢!

编辑:

感谢您对所有的答案这对我帮助很大,了解异步数据库操作的一般性问题。 dblink方法适用于我。如果使用相同的数据库,则不需要指定IP /端口/用户:

SELECT * FROM current_database() INTO _db_name; 
PERFORM dblink_connect('dbname=' || _db_name); 
PERFORM dblink_exec('UPDATE interpolation_jobs SET status = ''running'' WHERE id =' || _job_id); 

-- 
-- ... some extensive database computations ... 
-- 

PERFORM dblink_exec('UPDATE interpolation_jobs SET status = ''done'' WHERE id =' || _job_id); 
PERFORM dblink_disconnect(); 
+0

总之:没有。状态表的更新是事务的一部分,只有在事务提交后才能被其他进程看到。你需要异步通知来完成你想要的。请参阅精细手册中的'LISTEN'或'NOTIFY'。 – wildplasser 2013-04-29 10:51:51

回答

2

您可以使用dblink连接到你的数据库,并执行将在immiedietely COMMITED查询:

CREATE OR REPLACE FUNCTION interpolate_values (_job_id INTEGER) 
RETURNS VOID 
LANGUAGE plpgsql VOLATILE 
AS $$ 
DECLARE 
_conn TEXT; 
_status TEXT; 
BEGIN 
    _conn:='hostaddr=127.0.0.1 port=5433 dbname=<db> user=<user> password=<pass>'; 
    _status='running'; 
    PERFORM dblink_exec(_conn,'UPDATE interpolation_jobs SET status = '''||_status||''', progress = 0.0 WHERE id ='||_job_id); 
    PERFORM pg_sleep(10); --simulate some time consuming calculations 
    _status='finished'; 
    PERFORM dblink_exec(_conn,'UPDATE interpolation_jobs SET status = '''||_status||''', progress = 100.0 WHERE id ='||_job_id); 
END; 
$$; 
+0

谢谢。我以为我提到了dblink,但是当检查我的答案时,我发现我忘了。哎呦。 – 2013-05-01 01:41:05

2

您看起来想要的是脏读或脏写。这些在PostgreSQL中不可用,并且不可能永远支持。

近亲是一种自主交易。同样,PostgreSQL也不支持这些功能,但正在进行添加它们的工作。

你会发现,即使有自主交易,编写自己的高效排队系统也很困难。不要走这条路,用一个已经写好的人。排队系统是写得好,特别是针对RDBMS。像ZeroMQ,RabbitMQ,PGQ等现有系统可能是值得评估的替代品。

最近有关于为SELECT ... FOR UPDATE添加一项功能的讨论,它可以让PostgreSQL跳过锁定的行并获取未锁定的第一行。这个功能目前还不可用,并且在绝对最早的时候才能使用到9.4,所以不要屏住呼吸。