POSTGRES (9.6) — Циклические обновления, чтобы избежать нехватки памяти

#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 заявления.