PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Atualizando linhas do banco de dados sem travar a tabela no PostgreSQL 9.2

MVCC


Primeiro, se "operações normais" consistem em SELECT consultas, o modelo MVCC cuidará disso automaticamente. UPDATE não bloqueia SELECT e vice versa. SELECT só vê dados confirmados (ou o que foi feito na mesma transação), então o resultado do grande UPDATE permanece invisível para outras transações até que seja feito (confirmado).

Desempenho / inchaço


Se você não tem outros objetos referenciando essa tabela,
e você não tem operações de gravação simultâneas (que seriam perdidas!),
e você pode pagar um cadeado exclusivo muito curto na mesa,
e você tem espaço em disco adicional, é claro:
Você pode manter o bloqueio no mínimo criando uma versão atualizada da tabela em segundo plano. Certifique-se de que tem tudo para ser um substituto imediato, elimine o original e renomeie o dupe.
CREATE TABLE tbl_new (LIKE tbl_org INCLUDING CONSTRAINTS);

INSERT INTO tbl_new 
SELECT col_a, col_b, array[col] aS col_c
FROM   tbl_org;

Estou usando CREATE TABLE (LIKE .. INCLUDING CONSTRAINTS) , porque (citando o manual aqui):

As restrições não nulas são sempre copiadas para a nova tabela. CHECK restrições só serão copiadas se INCLUDING CONSTRAINTS é especificado; outros tipos de restrições nunca serão copiados.

Certifique-se de que a nova mesa está pronta. Então:
DROP tbl_org;
ALTER TABLE tbl_new RENAME TO tbl_org;

Resulta em uma janela de tempo muito curta, onde a mesa é bloqueada exclusivamente.

Isso é realmente apenas sobre o desempenho. Ele cria uma nova tabela sem qualquer inchaço rapidamente. Se você tiver chaves ou visualizações estrangeiras, ainda poderá seguir esse caminho, mas precisará preparar um script para descartar e recriar esses objetos, criando potencialmente bloqueios exclusivos adicionais.

Gravações simultâneas


Com operações de gravação simultâneas, tudo o que você pode fazer é dividir sua atualização em partes. Você não pode fazer isso em uma única transação, pois os bloqueios só são liberados no final de uma transação.

Você poderia empregar dblink , que pode iniciar transações independentes em outro banco de dados, incluindo ele mesmo. Dessa forma, você pode fazer tudo em um único DO instrução ou uma função plpgsql com um loop. Aqui está uma resposta vagamente relacionada com mais informações sobre o dblink:
  • Eliminar ou criar banco de dados do procedimento armazenado no PostgreSQL

Sua abordagem com cursores


Um cursor dentro da função não comprará nada . Qualquer função é incluída em uma transação automaticamente, e todos os bloqueios são liberados apenas no final da transação. Mesmo que você tenha usado CLOSE cursor (o que você não faz) liberaria apenas alguns recursos, mas não liberar bloqueios adquiridos na mesa. Cito o manual:

CLOSE fecha o portal subjacente a um cursor aberto. Isso pode ser usado para liberar recursos antes do final da transação ou para liberar a variável cursor para ser aberta novamente.

Você precisaria executar separado transações ou (ab) use dblink que faz isso por você.