#postgresql #postgresql-9.5
Вопрос:
У меня есть таблица базы данных, в которой я хочу просто обновить значение столбца для всех записей, имеющих определенное значение в другом столбце. Кажется, я не могу понять, как заставить пакетные обновления работать с помощью запросов postgres.
Текущая структура таблицы выглядит следующим образом:
placed_orders ( order_id uuid, source char(1), -- 'A', 'B', or 'C' submitted char(1), -- 'Y' or 'N' . . . )
Я хочу просто обновить источник всех строк placed_order до «B», где отправлено «Y», что обычно было бы так же просто, как запустить:
UPDATE placed_orders SET source='B' WHERE submitted='Y' AND source!='B';
Таблица довольно большая и содержит более 5 миллионов записей, и если бы я просто выполнил вышеприведенный запрос, чтобы обновить все записи сразу, я столкнулся бы с ошибками нехватки памяти, поэтому сейчас я рассматриваю возможность пакетного обновления.
Приведенный ниже запрос-это то, что у меня есть до сих пор, я новичок в циклах, объявлении переменных и изменении их значений:
DO $test$ DECLARE batch_size int := 1000; current_offset int := 0; records_to_update int := 0; BEGIN SELECT COUNT(1) INTO records_to_update FROM placed_orders WHERE submitted='Y' AND source !='B'; FOR j IN 0..records_to_update BY batch_size LOOP UPDATE placed_orders SET source = 'B' WHERE order_id IN (SELECT order_id FROM placed_orders WHERE submitted='Y' AND source!='B' ORDER BY order_id ASC OFFSET current_offset LIMIT batch_size); current_offset := current_offset batch_size; END LOOP; END $test$;
При выполнении этого запроса я все равно получаю ошибку памяти. Кто-нибудь знает, как заставить его обновляться настоящими пакетами?
Комментарии:
1. У вас не хватает оперативной памяти или места на диске? В чем именно заключается сообщение об ошибке? Работает ли postgresql в Windows или linux?
2. В Postgres an
UPDATE
-этоDELETE/INSERT
операция, которая означает, что для каждой записи у вас есть старая(DELETE
) и новая(INSERT
) строки. Проблема в том, что даже вDO
функции все происходит в одной транзакции, поэтому вы создаете множество кортежей(старых и новых) перед фиксацией. В более поздних версиях Postgres вы можете выполнять коммиты внутриDO
, чтобы смягчить это. Вам лучше всего надеяться, что вы сделаете это в сценарии, где вы можетеUPDATE
делать это партиями,COMMIT
а затемVACUUM
после каждой партии.3. Он работает на виртуальной машине Linux. там написано «из общей памяти».
4. Спасибо за информацию, @AdrianKlaver! Я подумал, что это может быть так, так как я нашел примеры с фиксациями внутри цикла, но это не сработало с моей текущей версией postgres.
5. Просто установите
max_parallel_workers_per_gather
значение 0 и запустите обновление в одной инструкции. 5 миллионов строк-это не большая таблица. Для подробного анализа (если это не поможет), пожалуйста, предоставьтеEXPLAIN
выходные данные для вашегоUPDATE
заявления.