LINUX.ORG.RU

Ошибка canceling statement due to statement timeout

 ,


0

1

Использую PGSQL. Есть таблица записей ~ 1000 000 записей

CREATE TABLE forms (
    id serial PRIMARY KEY,
    account INT NOT NULL,
    author text,
    salary INT NOT NULL
);
INSERT INTO  forms(account, author, salary) VALUES 
(1100889, 'Иванов', 30),
(1100889, 'Петров', 40),
(4443, 'Сидоров', 40),
(1100889, 'Сергеев', 50)

При авторизации пользователя в аккаунт идет пересчет поля salary в целом по аккаунту для всех пользователей

UPDATE forms
SET salary = (SELECT....)
WHERE account = 1100889
Перед обновление делаю блокировку по аккаунту с таймаутом 5 секунд.
BEGIN ISOLATION LEVEL READ COMMITTED READ WRITE;
SET LOCAL statement_timeout = '5000ms'; 
SELECT PG_ADVISORY_XACT_LOCK("lock_id") FROM (
                SELECT UNNEST('{1100889}'::BIGINT[]) AS "lock_id"
            ) LocksId      
RESET statement_timeout
В процессе обновления могут выполнятся обновления по конкретному сотруднику из этого аккаунта, я также ставлю блокировку по аккаунту.
UPDATE forms
SET salary = 100
WHERE account = 1100889 AND author = 'Иванов'
Когда общий запрос обновления по аккаунту (большой аккаунт) выполняется долго > 5 секунд, то падает ошибка на второй запрос обновления по сотруднику ошибка canceling statement due to statement timeout. Понятно, что оптимальное решение ускорить запрос расчета целиком по аккаунту.

Плохо разбираюсь в тебе блокировок в PGSQL, просьба подсказать как исправить ситуацию с точки зрения блокировок, в какую сторону смотреть?

Перемещено hobbit из general

Тебе дали изолированные транзакции. Нет не хочу, хочу жрать блокировки.

no-such-file ★★★★★ ()

Зачем вообще нужно statement_timeout = '5000ms'? Оно даже на одинаковых объёмах данных в 100% случаев гарантированно не отрабоает.

PhysShell ()
Ответ на: комментарий от polin11

У нас кремниевой долине, для синхронизации данных в двух базах Кулибины родили следующий алгоритм: (1) сначала проверяется номер ревизии двух баз, если на приёмнике устаревшая ревизия, (2) начинается обновление до актуальной на основе базы-источника, (3) в конце сравниваются данные на идентичность.

Редко, но бывает случаются сбои в матрице, когда источник изменился на момент выполнения шага (2). Тогда происходит откат изменений и процесс просто запускается повторно. Задача с тем, что в ОП не один в один, но краеугольный камень в виде возможности словить обновление во время уже запущенного обновления присутствует.

Не фонтан, но возня с блокировками на мой, не обременённый большим опытом работы с БД взгляд, выглядит менее предсказуемо. Гарантий, что апдейт в принципе выполнится за n секунд нет.

Испытываю скудность в ассортименте предложений, кроме банального увеличения таймаута, ну и посмотреть план запроса на возможность оптимизации — как ещё извернуться в данной ситуации самому было бы интересно узнать.

PhysShell ()

общий запрос обновления по аккаунту (большой аккаунт) выполняется долго > 5 секунд

Насколько большой?

При авторизации пользователя в аккаунт идет пересчет поля salary в целом по аккаунту для всех пользователей

UPDATE forms
SET salary = (SELECT....)
WHERE account = 1100889

Не понял, ты что, всем пользователям проставляешь одинаковое значение salary?

korvin_ ★★★★★ ()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.