Antipadrões PostgreSQL: lutando contra as hordas de “mortos”

As peculiaridades dos mecanismos internos do PostgreSQL permitem que ele seja muito rápido em algumas situações e “pouco rápido” em outras. Hoje vamos nos concentrar em um exemplo clássico de conflito entre como um SGBD funciona e o que o desenvolvedor faz com ele - Princípios UPDATE vs MVCC.

Breve história de ótimo artigo:

Quando uma linha é modificada por um comando UPDATE, duas operações são realmente executadas: DELETE e INSERT. EM versão atual da string xmax é igual ao número da transação que executou o UPDATE. Então é criado nova versão a mesma linha; seu valor xmin coincide com o valor xmax da versão anterior.

Algum tempo após a conclusão desta transação, a versão antiga ou nova, dependendo COMMIT/ROOLBACK, será reconhecido "morto" (tuplas mortas) ao passar VACUUM de acordo com a tabela e apagado.

Antipadrões PostgreSQL: lutando contra as hordas de “mortos”

Mas isso não acontecerá imediatamente, mas problemas com os “mortos” podem ser adquiridos muito rapidamente - com repetidos ou atualização em massa de registros em uma mesa grande, e um pouco mais tarde você encontrará a mesma situação VACUUM não será capaz de ajudar.

Nº 1: gosto de movê-lo

Digamos que seu método de lógica de negócio esteja funcionando sozinho e de repente ele percebe que seria necessário atualizar o campo X em algum registro:

UPDATE tbl SET X = <newX> WHERE pk = $1;

Então, à medida que a execução avança, verifica-se que o campo Y também deve ser atualizado:

UPDATE tbl SET Y = <newY> WHERE pk = $1;

... e depois também Z - por que perder tempo com ninharias?

UPDATE tbl SET Z = <newZ> WHERE pk = $1;

Quantas versões deste registro temos agora no banco de dados? Sim, 4 peças! Destes, um é relevante e 3 terão que ser limpos depois de você pelo [auto]VACUUM.

Não faça assim! Usar atualizando todos os campos em uma solicitação — quase sempre a lógica do método pode ser alterada assim:

UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;

#2: O uso É DISTINTO DE, Luke!

Então, você ainda queria atualizar muitos, muitos registros em uma tabela (durante a utilização de um script ou conversor, por exemplo). E algo assim entra no script:

UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;

Uma solicitação semelhante a esta é encontrada com bastante frequência e quase sempre não para preencher um novo campo vazio, mas para corrigir alguns erros nos dados. Ao mesmo tempo, ela mesma a exatidão dos dados existentes não é levada em consideração - mas em vão! Ou seja, o disco é reescrito, mesmo que contivesse exatamente o que se queria – mas por quê? Vamos consertar:

UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;

Muitas pessoas não estão cientes da existência de um operador tão maravilhoso, então aqui está uma folha de dicas sobre IS DISTINCT FROM e outros operadores lógicos para ajudar:
Antipadrões PostgreSQL: lutando contra as hordas de “mortos”
... e um pouco sobre operações em complexos ROW()-expressões:
Antipadrões PostgreSQL: lutando contra as hordas de “mortos”

#3: Reconheço meu amor por... bloquear

Corre dois processos paralelos idênticos, cada um dos quais tenta marcar a entrada como “em andamento”:

UPDATE tbl SET processing = TRUE WHERE pk = $1;

Mesmo que esses processos realmente façam coisas independentes um do outro, mas dentro do mesmo ID, o segundo cliente ficará “bloqueado” nesta solicitação até que a primeira transação seja concluída.

Decisão nº 1: a tarefa é reduzida à anterior

Vamos adicioná-lo novamente IS DISTINCT FROM:

UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;

Dessa forma, a segunda solicitação simplesmente não mudará nada no banco de dados, tudo já está como deveria estar - portanto, o bloqueio não ocorrerá. A seguir, processamos o fato de “não encontrar” o registro no algoritmo aplicado.

Decisão nº 2: bloqueios consultivos

Um grande tópico para um artigo separado, no qual você pode ler sobre métodos de aplicação e “rake” de bloqueio recomendado.

Decisão nº 3: chamadas estúpidas

Mas é exatamente isso que deveria acontecer com você trabalho simultâneo com o mesmo registro? Ou você bagunçou os algoritmos de chamada da lógica de negócios do lado do cliente, por exemplo? E se você pensar sobre isso?..

Fonte: habr.com

Adicionar um comentário