Как удалить несколько больших объектов большого размера в Postgres - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть миллион строк в таблице pg_largeobject_metadata, которую я хочу удалить. Что я пробовал до сих пор:

  • Простой выбор lo_unlink(oid) отлично работает
  • A perform lo_unlink(oid) в цикле из 10000 строк также будет работать нормально
  • Поэтому, когда я рекурсивно удаляю несколько строк, я получаю эту ошибку. Я не могу увеличить max_locks_per_transaction, потому что он управляется AWS.

ОШИБКА: недостаточно общей памяти СОВЕТ: Вам может понадобиться увеличить max_locks_per_transaction. КОНТЕКСТ: оператор SQL «SELECT lo_unlink (c_row.oid)» функция PL / pgSQL inline_code_block строка 21 в Состояние SQL PERFORM: 53200

Вот программа, которую я пытался написать, но я все еще получаю Недостаточно общей памяти ОШИБКА.

DO $proc$
DECLARE
v_fetch     bigInt;
v_offset    bigInt;
nbRows      bigInt;
c_row       record;
c_rows      CURSOR(p_offset bigInt, p_fetch bigInt) FOR SELECT oid FROM pg_largeobject_metadata WHERE oid BETWEEN 1910001 AND 2900000 OFFSET p_offset ROWS FETCH NEXT p_fetch ROWS ONLY;

BEGIN
v_offset    := 0;
v_fetch     := 100;
select count(*) into nbRows FROM pg_largeobject_metadata WHERE oid BETWEEN 1910001 AND 2900000;
RAISE NOTICE 'End loop nbrows = %', nbRows;
LOOP                                        -- Loop the different cursors 
    RAISE NOTICE 'offseter = %', v_offset;          
    OPEN c_rows(v_offset, v_fetch);
    LOOP                                    -- Loop through the cursor results
        FETCH c_rows INTO c_row;
        EXIT WHEN NOT FOUND;
        perform lo_unlink(c_row.oid);
    END LOOP;
    CLOSE c_rows;
    EXIT WHEN  v_offset > nbRows;
    v_offset := v_offset + v_fetch;         -- The next 10000 rows
END LOOP;
END;
$proc$;

Я использую Pg 9,5 Может кто-нибудь сталкивался с этой проблемой и мог бы помочь пожалуйста?

1 Ответ

0 голосов
/ 17 ноября 2018

Каждый lo_unlink() захватывает блокировку объекта, который он удаляет.Эти блокировки освобождаются только в конце транзакции, и они ограничены max_locks_per_transaction * (max_connections + max_prepared_transactions) (см. Управление блокировками ).По умолчанию max_locks_per_transaction равно 64, и повышение его на несколько порядков не является хорошим решением.

Типичное решение состоит в том, чтобы переместить внешний LOOP из вашего блока DO в ваш код на стороне клиента, изафиксировать транзакцию на каждой итерации (чтобы каждая транзакция удаляла 10000 крупных объектов и фиксировала).

Начиная с версии 11 PostgreSQL, возможен COMMIT внутри блока DO , точно так же, как управление транзакциейв процедурах возможно.

...