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

Uma visão geral do processamento VACUUM no PostgreSQL

O PostgreSQL não usa o mecanismo de atualização IN-PLACE, de acordo com a forma como o comando DELETE e UPDATE é projetado,

  • Sempre que operações DELETE são executadas, ela marca a tupla existente como DEAD em vez de remover fisicamente essas tuplas.
  • Da mesma forma, sempre que a operação UPDATE é executada, ela marca a tupla existente correspondente como DEAD e insere uma nova tupla (ou seja, operação UPDATE =DELETE + INSERT).

Assim, cada comando DELETE e UPDATE resultará em uma tupla DEAD, que nunca será usada (a menos que haja transações paralelas). Essas tuplas mortas levarão ao uso desnecessário de espaço extra, mesmo com o mesmo ou menos número de registros efetivos. Isso também é chamado de aumento de espaço no PostgreSQL. Como o PostgreSQL é amplamente utilizado como sistema de banco de dados relacional tipo OLTP, onde são realizadas operações INSERT, UPDATE e DELETE frequentes, haverá muitas tuplas DEAD e, portanto, consequências correspondentes. Portanto, o PostgreSQL exigia um forte mecanismo de manutenção para lidar com essas tuplas DEAD. VACUUM é o processo de manutenção que cuida de lidar com a tupla DEAD junto com mais algumas atividades úteis para otimizar a operação VACUUM. Vamos entender algumas terminologias para serem usadas posteriormente neste blog.

Mapa de visibilidade

Como o nome indica, ele mantém informações de visibilidade sobre páginas contendo apenas tuplas que são conhecidas por serem visíveis para todas as transações ativas. Para cada página, um bit é usado. Se o bit for definido como 1 significa que todas as tuplas da página correspondente estão visíveis. O bit definido como 0 significa que não há espaço livre na página fornecida e as tuplas podem ser visíveis para todas as transações.

O mapa de visibilidade é mantido para cada relação (tabela e índice) e é associado ao lado das relações principais, ou seja, se o nome do nó do arquivo de relação for 12345, o arquivo de visibilidade será armazenado no arquivo paralelo 12345_vm.

Mapa do Espaço Livre

Mantém informações de espaço livre contendo detalhes sobre o espaço disponível na relação. Isso também é armazenado no arquivo paralelo ao arquivo principal de relação, ou seja, se o nome do nó do arquivo de relação for 12345, o arquivo de mapa de espaço livre será armazenado no arquivo paralelo 12345_fsm.

Congelar Tupla

O PostgreSQL usa 4 bytes para armazenar o id de transação, o que significa que um máximo de 2 bilhões de transações podem ser geradas antes de terminar. Agora considere ainda neste momento alguma tupla contém id de transação inicial, digamos 100, então para a nova transação (que usa a transação em volta), digamos 5, o id de transação 100 irá olhar para o futuro e não será capaz de ver os dados adicionados /modificado por ele mesmo que fosse realmente no passado. Para evitar esse id de transação especial, FrozenTransactionId (igual a 2) é atribuído. Este id de transação especial é sempre considerado no passado e estará visível para todas as transações.

VÁCUO

A tarefa principal do VACUUM é recuperar o espaço de armazenamento ocupado por tuplas DEAD. O espaço de armazenamento recuperado não é devolvido ao sistema operacional, em vez disso, eles são apenas desfragmentados na mesma página, portanto, estão disponíveis para serem reutilizados pela futura inserção de dados na mesma tabela. Enquanto a operação VACUUM está acontecendo em uma tabela específica, outras operações READ/WRITE podem ser feitas simultaneamente na mesma tabela, pois o bloqueio exclusivo não é realizado na tabela específica. Caso um nome de tabela não seja especificado, VACUUM será executado em todas as tabelas do banco de dados. A operação VACUUM executa abaixo uma série de operações dentro de um bloqueio ShareUpdateExclusive:

  • Verifique todas as páginas de todas as tabelas (ou tabela especificada) do banco de dados para obter todas as tuplas mortas.
  • Congele tuplas antigas, se necessário.
  • Remova a tupla de índice apontando para as respectivas tuplas DEAD.
  • Remova as tuplas DEAD de uma página correspondente a uma tabela específica e realoque as tuplas ativas na página.
  • Atualize o mapa de espaço livre (FSM) e o mapa de visibilidade (VM).
  • Trunque a última página, se possível (se houver tuplas DEAD que foram liberadas).
  • Atualize todas as tabelas de sistema correspondentes.

Como podemos ver nas etapas de trabalho acima para VACUUM, fica claro que é uma operação muito cara, pois precisa processar todas as páginas da relação. Portanto, é muito necessário pular possíveis páginas que não precisam ser aspiradas. Como o mapa de visibilidade (VM) fornece informações da página onde, se não houver espaço livre, pode-se supor que o vácuo de página correspondente não é necessário e, portanto, essa página pode ser ignorada com segurança.

Como VACUUM percorre todas as páginas e todas as suas tuplas, então aproveita a oportunidade para fazer outra tarefa importante de congelar as tuplas qualificadas.

VÁCUO Completo

Conforme discutido na seção anterior, embora VACUUM remova todas as tuplas DEAD e desfragmente a página para uso futuro, isso não ajuda a reduzir o armazenamento geral da tabela, pois o espaço não é liberado para o sistema operacional. Suponha uma tabela tbl1 que o armazenamento total atingiu 1,5 GB e desse 1 GB ocupado por tupla morta, então após VACUUM outro aproximadamente 1 GB estará disponível para inserção de tupla adicional, mas ainda assim, o armazenamento total permanecerá como 1,5 GB.

Full VACUUM resolve esse problema liberando espaço e devolvendo-o ao sistema operacional. Mas isso tem um custo. Ao contrário de VACUUM, FULL VACUUM não permite operação paralela, pois leva um bloqueio exclusivo na relação recebendo FULL VACUUMed. Abaixo estão os passos:

  • Tem um bloqueio exclusivo na relação.
  • Crie um arquivo de armazenamento paralelo vazio.
  • Copie todas as tuplas ativas do armazenamento atual para o armazenamento recém-alocado.
  • Em seguida, libere o armazenamento original.
  • Libere o bloqueio.

Assim como fica claro nas etapas também, ele terá armazenamento necessário apenas para os dados restantes.

Aspiração automática

Ao invés de fazer VACUUM manualmente, o PostgreSQL suporta um demônio que aciona automaticamente VACUUM periodicamente. Toda vez que o VACUUM acorda (por padrão, 1 minuto), ele invoca vários trabalhos (dependendo dos processos de configuração do autovacuum_worker).

Auto-vacuum workers fazem processos VACUUM simultaneamente para as respectivas tabelas designadas. Como o VACUUM não faz nenhum bloqueio exclusivo nas tabelas, ele não afeta (ou é mínimo) outro trabalho de banco de dados.

A configuração do Auto-VACUUM deve ser feita com base no padrão de uso do banco de dados. Não deve ser muito frequente (pois desperdiçará o despertar do trabalhador, pois pode não haver ou muito poucas tuplas mortas) ou muito atrasado (isso causará muitas tuplas mortas juntas e, portanto, inchaço da mesa).

VÁCUO ou VÁCUO Completo

Idealmente, o aplicativo de banco de dados deve ser projetado de forma que não haja necessidade de FULL VACUUM. Conforme explicado acima, FULL VACUUM recria o espaço de armazenamento e coloca de volta os dados, portanto, se houver apenas menos tuplas mortas, o espaço de armazenamento será recriado imediatamente para colocar de volta todos os dados originais. Além disso, como FULL VACUUM tem bloqueio exclusivo na tabela, ele bloqueia todas as operações na tabela correspondente. Portanto, fazer FULL VACUUM às vezes pode diminuir a velocidade geral do banco de dados.

Em resumo Full VACUUM deve ser evitado a menos que se saiba que a maior parte do espaço de armazenamento é devido a tuplas mortas. A extensão do PostgreSQL pg_freespacemap pode ser usada para obter uma boa dica sobre o espaço livre.

Vamos ver um exemplo do processo VACUUM explicado.

Primeiro, vamos criar uma tabela demo1:

postgres=# create table demo1(id int, id2 int);

CREATE TABLE

E insira alguns dados lá:

postgres=# insert into demo1 values(generate_series(1,10000), generate_series(1,

10000));

INSERT 0 10000

postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');

 npages | average_freespace_ratio

--------+-------------------------

  45 |                0.00

(1 row)

Agora, vamos excluir os dados:

postgres=# delete from demo1 where id%2=0;

DELETE 5000

E execute um vácuo manual:

postgres=# vacuum demo1;

VACUUM

postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');

 npages | average_freespace_ratio

--------+-------------------------

  45 |               45.07

(1 row)

Este espaço livre agora está disponível para ser reutilizado pelo PostgreSQL, mas se você quiser liberar esse espaço para o sistema operacional, execute:

postgres=# vacuum full demo1;

VACUUM

postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');

 npages | average_freespace_ratio

--------+-------------------------

  23 |                0.00

(1 row)

Conclusão


E este foi um pequeno exemplo de como funciona o processo VACUUM. Felizmente, graças ao processo de auto vácuo, na maioria das vezes e em um ambiente PostgreSQL comum, você não precisa pensar nisso porque é gerenciado pelo próprio mecanismo.