У меня есть простой блок PL / PGSQL Postgres 9.5 , который перебирает записи в таблице и условно обновляет некоторые записи.
Вот упрощенный пример:
DO $$
DECLARE
-- Define a cursor to loop through records
my_cool_cursor CURSOR FOR
SELECT
u.id AS user_id,
u.name AS user_name,
u.email AS user_email
FROM users u
;
BEGIN
FOR record IN my_cool_cursor LOOP
-- Simplified example:
-- If user's first name is 'Anjali', set email to NULL
IF record.user_name = 'Anjali' THEN
BEGIN
UPDATE users SET email = NULL WHERE id = record.user_id;
END;
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
Я бы хотел выполнить этот блок непосредственно для моей базы данных (из моего приложения, через консоль и т. Д.). Я не хочу создать FUNCTION()
или хранимую процедуру для выполнения этой операции.
Проблема
Проблема заключается в том, что CURSOR
и LOOP
создают блокировку на уровне таблицы для моей таблицы users
, поскольку все, что находится между внешним BEGIN...END
, выполняется всделка. Это блокирует любые другие ожидающие запросы к нему. Если users
достаточно велико, это блокирует его на несколько секунд или даже минут.
То, что я пытался
Я пытался COMMIT
после каждого UPDATE
, чтобы периодически очищать транзакцию и блокировку. Я был удивлен, увидев это сообщение об ошибке:
ERROR: cannot begin/end transactions in PL/pgSQL
HINT: Use a BEGIN block with an EXCEPTION clause instead.
Я не совсем уверен, как это сделать. Это просит меня поднять EXCEPTION
, чтобы заставить COMMIT
? Я попытался прочитать документацию по ошибкам перехвата , но там упоминается только ROLLBACK
, поэтому я не вижу пути к COMMIT
.
- Как мне периодически
COMMIT
транзакция внутри LOOP
выше? - В целом, мой подход даже правильный? Есть ли лучший способ перебирать записи без блокировки таблицы?