Анализ производства Postgres UPDATE - медлительность запросов RETURNING - PullRequest
0 голосов
/ 28 февраля 2019

Мы запускаем веб-приложение, в котором в среднем 10 000 активных пользователей, обслуживаемое 6 веб-узлами и поддерживаемое Postgres 9.4.6.

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

Это небольшая таблица, внутренняя реализация последовательности, в основном (устаревшее приложение), отслеживающая уникальные идентификаторы для других таблиц:

CREATE TABLE ids_for_records
(
  tableid integer NOT NULL,
  id bigint NOT NULL,
  CONSTRAINT ids_for_records_pk PRIMARY KEY (tableid)
)
WITH (
  OIDS=FALSE
);

В этой таблице всего около 200 записей.Наши узлы веб-приложений используют этот запрос, чтобы получить пакет идентификаторов, предназначенных исключительно для себя:

UPDATE ids_for_records
SET id = id + <batchsize>
WHERE tableid = <unique-internal-table-id>
RETURNING id;

Мне нужно выяснить, почему производительность этого запроса значительно упала в последние дни:в среднем около 1 секунды, но иногда и 30-60 секунд.Во время высокой нагрузки все узлы выполняют одни и те же запросы параллельно для нескольких соединений.

ОБНОВЛЕНИЕ : Запрос информации о блокировках (из pg_lock, pg_class и pg_stat_activity), удерживаемых одним (медленный запрос показал, что точно такой же запрос из других транзакций, которые ожидаются.Таким образом, у нас есть одновременные транзакции, пытающиеся обновить (увеличить значение идентификатора) одну и ту же строку, таким образом, одна активная со всеми необходимыми блокировками блокирует все остальные.

В противном случае база данных исправна, наша операционная команда не обнаружила никаких проблем с хранилищем, памятью или соединениями;однако размер другой таблицы недавно достиг 64 ГБ, что может быть связано с этим.

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

1 Ответ

0 голосов
/ 28 февраля 2019

Ниже приведены некоторые догадки, пожалуйста, исправьте меня, где я угадал.

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

Блокировки удерживаются на протяжении всей транзакции, поэтому, вероятно, обработка пакета в той же транзакции, что и оператор UPDATE, являетсяблокирование одновременных сеансов.

Решение заключается в использовании последовательностей.Поскольку вы построили свое решение модульно, используя одну центральную функцию, решить проблему не составит труда.

Задача состоит в том, чтобы получить целые партии значений последовательности.Вы можете сделать это безопасным способом, защитив setval с помощью консультативных блокировок , которые можно разблокировать до завершения транзакции.См. в моем блоге для примера, как это можно сделать.

...