База данных действительно не лучший инструмент для сбора множества небольших обновлений, но, поскольку я не знаю ваших требований к запросам и ACID, я не могу порекомендовать что-то еще. Если это приемлемый подход, агрегация обновлений на стороне приложения, предложенная zzzeek, может значительно снизить загрузку обновлений.
Существует аналогичный подход, который может обеспечить вам долговечность и возможность запрашивать более свежие данные при некоторых затратах на производительность. Создайте буферную таблицу, которая может собирать изменения в значения, которые необходимо обновить, и вставьте туда изменения. Через равные промежутки времени транзакция переименовывает таблицу во что-то другое и вместо нее создает новую таблицу. Затем в транзакции объедините все изменения, выполните соответствующие обновления основной таблицы и обрежьте буферную таблицу. Таким образом, если вам нужен непротиворечивый и свежий снимок любых данных, вы можете выбрать их из основной таблицы и объединить все изменения из активных и переименованных буферных таблиц.
Однако, если ни то, ни другое не приемлемо, вы также можете настроить базу данных, чтобы лучше справляться с большими нагрузками при обновлении.
Чтобы оптимизировать обновление, убедитесь, что PostgreSQL может использовать кортежи только для кучи для хранения обновленных версий строк. Для этого убедитесь, что в часто обновляемых столбцах отсутствуют индексы, и измените fillfactor на значение, меньшее 100% по умолчанию. Вам нужно будет самостоятельно определить подходящий коэффициент заполнения, так как он сильно зависит от деталей рабочей нагрузки и машины, на которой он работает. Коэффициент заполнения должен быть достаточно низким, чтобы почти все обновления помещались на одну и ту же страницу базы данных, прежде чем автоочистка сможет очистить старые невидимые версии. Вы можете настроить параметры автоочистки для компромисса между плотностью базы данных и расходом вакуума. Кроме того, примите во внимание, что любые длинные транзакции, включая статистические запросы, будут удерживать кортежи, которые изменились после запуска транзакции. См. Представление pg_stat_user_tables , чтобы узнать, что настраивать, особенно отношение n_tup_hot_upd к n_tup_upd и n_live_tup к n_dead_tup .
Тяжелое обновление также создаст интенсивную загрузку журнала записи (WAL). Настройка поведения WAL ( документы для настроек ) поможет снизить это. В частности, большее число checkpoint_segments и большее checkpoint_timeout могут значительно снизить нагрузку ввода-вывода, позволяя большему количеству обновлений происходить в памяти. Посмотрите соотношение checkpoints_timed и checkpoints_req в pg_stat_bgwriter, чтобы увидеть, сколько контрольных точек происходит, потому что достигнут любой из этих пределов. Повышение ваших shared_buffers так, чтобы рабочий набор помещался в память, также поможет. Проверьте «buffers_checkpoint» и «buffers_clean + buffers_backend», чтобы узнать, сколько было написано для удовлетворения требований контрольной точки по сравнению с нехваткой памяти.