2013-04-29 75 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,所以不要屏住呼吸。