Как я могу обновить несколько элементов из запроса выбора в Postgres?

Я использую node.js, node-postgres и Postgres, чтобы собрать скрипт для обработки большого количества данных из таблицы. Я также использую кластерный модуль, поэтому я не зацикливаюсь на одном потоке.

Я не хочу, чтобы один из дочерних процессов в кластере дублировал обработку другого. Как я могу обновить строки, которые я только что получил из запроса выбора, без возможности другого процесса или запроса, также выбравших те же строки?

Я предполагаю, что мой SQL-запрос будет выглядеть примерно так:

BEGIN;
SELECT * FROM mytable WHERE ... LIMIT 100;
UPDATE mytable SET status = 'processing' WHERE ...;
COMMIT;

Приношу свои извинения за плохое знание Postgres и SQL, я использовал его раньше в простом веб-приложении PHP и никогда раньше с node.js.


person Thomas Foster    schedule 02.01.2015    source источник
comment
Вы хотите написать FOR UPDATE, используя что-то вроде этого: stackoverflow.com/questions/18879584/   -  person Anthony    schedule 02.01.2015
comment
@Anthony Я посмотрю на FOR UPDATE, я не уверен, что он делает именно то, что я хочу делать.   -  person Thomas Foster    schedule 02.01.2015


Ответы (2)


Если вы используете многопоточное приложение, вы не можете и не должны использовать «для обновления» (в любом случае в основном потоке), вам нужно использовать рекомендательную блокировку. Каждый поток может запрашивать строку или множество строк, проверяя, что они не заблокированы, а затем блокировать их, чтобы ни один другой сеанс не использовал их. Это так просто в каждом потоке:

select * from mytab
where pg_try_advisory_lock(mytab.id)
limit 100

в конце обязательно снимите блокировки с помощью pg_advisory_unlock

person Joe Love    schedule 02.01.2015
comment
это может заблокировать все строки в таблице, но вернуть только их подмножество. - person Jasen; 05.01.2015

BEGIN;
UPDATE mytable SET status = 'processing' WHERE status <> "processing" and id in 
( selecy ID FROM mytable where status <> "processing" limit 100) returning * ;
COMMIT;

Есть вероятность, что произойдет сбой, если какой-либо другой запрос работал с теми же строками, поэтому, если вы получите сообщение об ошибке, повторяйте его, пока вы не получите какие-то данные или не вернут строки.

если у вас нет строк, либо вы закончили, либо есть слишком много других одновременных операций, подобных вашей.

person Jasen    schedule 05.01.2015