Reduzir o inchaço em tabelas e índices com a extensão pg_repack
É possível usar a extensão pg_repack para remover a sobrecarga de tabelas e índices como uma alternativa a VACUUM FULL. Esta extensão é compatível com o RDS para PostgreSQL versões 9.6.3 e posteriores. Para ter mais informações sobre a extensão pg_repack e a recriação da tabela inteira, consulte a documentação de projetos do GitHub
Ao contrário de VACUUM FULL, a extensão pg_repack requer um bloqueio exclusivo (AccessExclusiveLock) somente por um curto período durante a operação de recriação da tabela nos seguintes casos:
-
Criação inicial da tabela de logs: uma tabela de logs é criada para registrar as alterações que ocorrem durante a cópia inicial dos dados, conforme mostrado no seguinte exemplo:
postgres=>\dt+ repack.log_* List of relations -[ RECORD 1 ]-+---------- Schema | repack Name | log_16490 Type | table Owner | postgres Persistence | permanent Access method | heap Size | 65 MB Description | -
Fase final de troca e descarte.
Para o restante da operação de recriação, ela só precisa de um bloqueio ACCESS SHARE na tabela original para copiar as linhas dela para a nova tabela. Isso ajuda as operações INSERT, UPDATE e DELETE a prosseguir normalmente.
Recomendações
As recomendações a seguir se aplicam ao remover a sobrecarga das tabelas e dos índices usando a extensão pg_repack:
-
Realize a recriação fora do horário comercial ou durante uma janela de manutenção para minimizar o impacto na performance de outras atividades do banco de dados.
-
Monitore atentamente as sessões de bloqueio durante a atividade de recriação e garanta que não haja nenhuma atividade na tabela original que possa bloquear
pg_repack, especificamente durante a fase final de troca e descarte, quando ela precisa de um bloqueio exclusivo na tabela original. Para ter mais informações, consulte Como identificar o que está bloqueando uma consulta. Ao ver uma sessão de bloqueio, é possível encerrá-la usando o comando a seguir após uma análise cuidadosa. Isso ajuda na continuação da
pg_repackpara concluir a recriação:SELECT pg_terminate_backend(pid); -
Ao aplicar as alterações acumuladas da tabela de logs de
pg_repack'sem sistemas com uma taxa de transação muito alta, o processo de aplicação pode não ser capaz de acompanhar a taxa de alterações. Nesses casos,pg_repacknão conseguiria concluir o processo de aplicação. Para ter mais informações, consulte Monitorar a nova tabela durante a recriação. Se os índices estiverem muito sobrecarregados, uma solução alternativa será realizar uma recriação somente de índices. Isso também ajuda os ciclos de limpeza do índice do VACUUM a terminar mais rapidamente.É possível ignorar a fase de limpeza do índice usando o VACUUM manual do PostgreSQL versão 12, e ela é ignorada automaticamente durante o autovacuum de emergência do PostgreSQL versão 14. Isso ajuda o VACUUM a ser concluído mais rapidamente sem remover a sobrecarga do índice e serve apenas para situações de emergência, como evitar o VACUUM de encapsulamento. Para ter mais informações, consulte Evitar a sobrecarga nos índices no Guia do usuário do Amazon Aurora.
Pré-requisitos
-
A tabela deve ter PRIMARY KEY ou a restrição UNIQUE não nula.
-
A versão da extensão deve ser a mesma para o cliente e para o servidor.
-
Garanta que a instância do RDS tenha mais
FreeStorageSpacedo que o tamanho total da tabela sem a sobrecarga. Por exemplo, pense no tamanho total da tabela, incluindo TOAST e índices, como 2 TB, e a sobrecarga total na tabela, como 1 TB. OFreeStorageSpacenecessário deve ser maior do que o valor exibido pelo seguinte cálculo:2TB (Table size)-1TB (Table bloat)=1TBÉ possível usar a consulta a seguir para conferir o tamanho total da tabela e usar
pgstattuplepara gerar a sobrecarga. Para ter mais informações, consulte Diagnosticar a sobrecarga na tabela e no índice no Guia do usuário do Amazon Aurora.SELECT pg_size_pretty(pg_total_relation_size('table_name')) AS total_table_size;Esse espaço é recuperado após a conclusão da atividade.
-
Garanta que a instância do RDS tenha capacidade computacional e de E/S suficientes para lidar com a operação de recriação. Pense na possibilidade de aumentar a escala da classe de instância verticalmente para conseguir o equilíbrio ideal de performance.
Como usar a extensão pg_repack
-
Instale a extensão
pg_repackna instância de banco de dados RDS for PostgreSQL executando o comando a seguir.CREATE EXTENSION pg_repack; -
Execute os comandos a seguir para conceder acesso de gravação para recriar as tabelas de logs temporárias criadas pelo
pg_repack.ALTER DEFAULT PRIVILEGES IN SCHEMA repack GRANT INSERT ON TABLES TO PUBLIC; ALTER DEFAULT PRIVILEGES IN SCHEMA repack GRANT USAGE, SELECT ON SEQUENCES TO PUBLIC; -
Conecte-se ao banco de dados usando o utilitário de cliente
pg_repack. Use uma conta que tenha privilégiosrds_superuser. Como exemplo, suponha que a funçãords_testtenha os privilégiosrds_superuser. A sintaxe a seguir realiza apg_repackpara tabelas completas, incluindo todos os índices da tabela no banco de dadospostgres.pg_repack -hdb-instance-name.111122223333.aws-region.rds.amazonaws.com -Urds_test-kpostgresnota
É necessário se conectar usando a opção -k. Não há suporte para a opção -a.
A resposta do cliente
pg_repackfornece informações sobre as tabelas recriadas na instância de banco de dados.INFO: repacking table "pgbench_tellers" INFO: repacking table "pgbench_accounts" INFO: repacking table "pgbench_branches" -
A sintaxe a seguir recria uma única tabela
ordersincluindo índices no banco de dadospostgres.pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -Urds_test--tableorders-kpostgresA sintaxe a seguir recria somente os índices da tabela
ordersno banco de dadospostgres.pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -Urds_test--tableorders--only-indexes -kpostgres
Monitorar a nova tabela durante a recriação
-
O tamanho do banco de dados é aumentado pelo tamanho total da tabela menos a sobrecarga, até a fase de troca e descarte da recriação. É possível monitorar a taxa de crescimento do tamanho do banco de dados, calcular a velocidade da recriação e estimar aproximadamente o tempo necessário para concluir a transferência inicial dos dados.
Por exemplo, pense no tamanho total da tabela como 2 TB, o tamanho do banco de dados como 4 TB e a sobrecarga total na tabela como 1 TB. O valor do tamanho total do banco de dados exibido pelo cálculo no final da operação de recriação é o seguinte:
2TB (Table size)+4 TB (Database size)-1TB (Table bloat)=5TBÉ possível calcular aproximadamente a velocidade da operação de recriação criando uma amostra da taxa de crescimento em bytes entre dois pontos no tempo. Se a taxa de crescimento for de 1 GB por minuto, poderá levar mil minutos ou 16,6 horas aproximadamente para concluir a operação inicial de criação da tabela. Além da criação inicial da tabela, a
pg_repacktambém precisa aplicar as alterações acumuladas. O tempo necessário depende da taxa de aplicação das alterações em andamento, além das alterações acumuladas.nota
É possível usar a extensão
pgstattuplepara calcular a sobrecarga na tabela. Para ter mais informações, consulte pgstattuple. -
O número de linhas na tabela de logs
pg_repack's, no esquema de recriação, representa o volume de alterações pendentes para serem aplicadas à nova tabela após o carregamento inicial.É possível conferir a tabela de logs
pg_repack'sempg_stat_all_tablespara monitorar as alterações aplicadas à nova tabela.pg_stat_all_tables.n_live_tupindica o número de registros pendentes a serem aplicados à nova tabela. Para ter mais informações, consulte pg_stat_all_tables. postgres=>SELECT relname,n_live_tup FROM pg_stat_all_tables WHERE schemaname = 'repack' AND relname ILIKE '%log%';-[ RECORD 1 ]--------- relname | log_16490 n_live_tup | 2000000 -
É possível usar a extensão
pg_stat_statementspara descobrir o tempo gasto em cada etapa da operação de recriação. Isso é útil na preparação para aplicar a mesma operação de recriação em um ambiente de produção. É possível ajustar a cláusulaLIMITpara estender ainda mais a saída.postgres=>SELECT SUBSTR(query, 1, 100) query, round((round(total_exec_time::numeric, 6) / 1000 / 60),4) total_exec_time_in_minutes FROM pg_stat_statements WHERE query ILIKE '%repack%' ORDER BY total_exec_time DESC LIMIT 5;query | total_exec_time_in_minutes -----------------------------------------------------------------------+---------------------------- CREATE UNIQUE INDEX index_16493 ON repack.table_16490 USING btree (a) | 6.8627 INSERT INTO repack.table_16490 SELECT a FROM ONLY public.t1 | 6.4150 SELECT repack.repack_apply($1, $2, $3, $4, $5, $6) | 0.5395 SELECT repack.repack_drop($1, $2) | 0.0004 SELECT repack.repack_swap($1) | 0.0004 (5 rows)
A recriação é uma operação extraordinária, portanto, a tabela original não é afetada e não prevemos nenhum desafio inesperado que exija a recuperação da tabela original. Se a recriação falhar inesperadamente, você deverá inspecionar a causa do erro e resolvê-lo.
Depois que o problema for resolvido, descarte e recrie a extensão pg_repack no banco de dados em que a tabela existe e repita a etapa pg_repack. Além disso, a disponibilidade de recursos computacionais e a acessibilidade simultânea da tabela desempenham um papel crucial na conclusão oportuna da operação de recriação.