2013-04-29 4 views
2

Я работаю над функцией PL/pgSQL «interpolate_values» с некоторыми трудоемкими вычислениями. Стол под названием «interpolation_jobs» содержит информацию наблюдения о каждом вызове функции, например, что прогресс вызова функции с заданной job_id должен быть наблюдаемаНемедленное обновление в функциях PL/pgSQL

SELECT status FROM interpolation_jobs WHERE id = job_id; 

В столбце «Статус» содержит одно из значений «очередь» , '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, чтобы новые значения были доступны до вызова функции?

Спасибо!

EDIT:

Спасибо за все ваши ответы, которые помогли мне многое понять общие проблемы асинхронных операций базы данных. Подход dblink работает для меня. Не нужно указать IP/Port/User, если используется та же база данных:

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

ответ

2

Вы можете использовать dblink для подключения к базе данных и выполнить запрос, который будет immiedietely поручены:

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, но, проверяя мой ответ, я вижу, что забыл. Упс. –

2

Что вы, кажется, хотите грязное чтение или запись загрязнен. Они недоступны в PostgreSQL и вряд ли когда-либо будут поддерживаться.

Близкий родственник является автономной сделкой. Опять же, они не поддерживаются PostgreSQL, хотя работа по их добавлению выполняется.

Вы обнаружите, что даже при автономных транзакциях очень сложно написать собственную эффективную систему очередей. Не идите по этому пути, используйте того, кого уже написал. Системы массового обслуживания - hard, чтобы хорошо писать, в частности, на РСУБД. Существующие системы, такие как ZeroMQ, RabbitMQ, PGQ и т. Д., Могут оцениваться как альтернативы.

В последнее время обсуждалось добавление функции к SELECT ... FOR UPDATE, которая позволила PostgreSQL пропустить заблокированные строки и захватить первую строку, которая не заблокирована. Эта функция пока недоступна и будет недоступна до 9.4 в самое ближайшее время, поэтому не задерживайте дыхание.

Смежные вопросы