【问题标题】:Immediate update in PL/pgSQL functionsPL/pgSQL 函数的即时更新
【发布时间】:2013-05-02 22:25:57
【问题描述】:

我正在使用一些耗时的计算来处理 PL/pgSQL 函数“interpolate_values”。名为“interpolation_jobs”的表包含有关每个函数调用的监视信息,因此具有给定 job_id 的函数调用的进度应该可以通过

SELECT status FROM interpolation_jobs WHERE id = job_id;

“状态”列包含值“排队”、“运行”或“完成”之一。在函数开始时,状态从'queued'变为'running',最后设置为'done':

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();

【问题讨论】:

  • 简而言之:没有。状态表的更新是事务的一部分,只有在事务提交后才能被其他进程看到。你需要异步通知来完成你想要的。请参阅精美手册中的“LISTEN”或“NOTIFY”。

标签: postgresql plpgsql


【解决方案1】:

您似乎想要的是脏读或脏写。这些在 PostgreSQL 中不可用,并且可能永远不会被支持。

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

您会发现,即使使用自治事务,也很难编写自己的高效排队系统。不要走这条路,使用某人已经写过的。队列系统很难写得好,尤其是针对 RDBMS。 ZeroMQ、RabbitMQ、PGQ 等现有系统可能非常值得作为替代品进行评估。

最近有关于向SELECT ... FOR UPDATE 添加一个功能的讨论,该功能可以让 PostgreSQL 跳过锁定的行并抓取第一行未锁定的行。这个功能目前还不可用,最快也要到 9.4 才能使用,所以不要屏住呼吸。

【讨论】:

    【解决方案2】:

    您可以使用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;
    $$;
    

    【讨论】:

    • 谢谢。我以为我提到了 dblink,但是在检查我的答案时,我发现我忘了。哎呀。
    猜你喜欢
    • 1970-01-01
    • 2012-09-13
    • 2013-11-15
    • 2023-03-16
    • 2012-04-24
    • 2012-08-05
    • 1970-01-01
    • 2012-07-16
    • 2022-01-17
    相关资源
    最近更新 更多