立即更新PL / pgSQL函数

时间:2013-04-29 09:17:58

标签: postgresql plpgsql

我正在研究PL / pgSQL函数" interpolate_values"一些耗时的计算。一个名为" interpolation_jobs"包含有关每个函数调用的监视信息,以便可以通过

观察具有给定job_id的函数调用的进度。
SELECT status FROM interpolation_jobs WHERE 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();

2 个答案:

答案 0 :(得分:4)

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

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

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

最近讨论过向SELECT ... FOR UPDATE添加一个功能,让PostgreSQL跳过锁定的行并抓住未锁定的第一行。此功能尚未推出,最早在9.4之前无法使用,所以请勿屏住呼吸。

答案 1 :(得分:3)

您可以使用dblink连接到您的数据库并执行将立即提交的查询:

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;
$$;