

# Reduzir o inchaço em tabelas e índices com a extensão pg\$1repack
<a name="Appendix.PostgreSQL.CommonDBATasks.pg_repack"></a>

É 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](https://reorg.github.io/pg_repack/).

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
<a name="Appendix.PostgreSQL.CommonDBATasks.pg_repack.Recommen"></a>

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](https://repost.aws/knowledge-center/rds-aurora-postgresql-query-blocked). 

  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_repack` para concluir a recriação:

  ```
  SELECT pg_terminate_backend(pid);
  ```
+ Ao aplicar as alterações acumuladas da tabela de logs de `pg_repack's` em 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_repack` não conseguiria concluir o processo de aplicação. Para obter mais informações, consulte [Monitorar a nova tabela durante a recriação](#Appendix.PostgreSQL.CommonDBATasks.pg_repack.Monitoring). 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](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.diag-table-ind-bloat.html#AuroraPostgreSQL.diag-table-ind-bloat.AvoidinginIndexes) no Guia do usuário do Amazon Aurora.

## Pré-requisitos
<a name="Appendix.PostgreSQL.CommonDBATasks.pg_repack.Prereq"></a>
+ 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 `FreeStorageSpace` do 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. O `FreeStorageSpace` necessá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 `pgstattuple` para gerar a sobrecarga. Para ter mais informações, consulte [Diagnosticar a sobrecarga na tabela e no índice](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.diag-table-ind-bloat.html) 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`**

1. Instale a extensão `pg_repack` na instância de banco de dados RDS for PostgreSQL executando o comando a seguir.

   ```
   CREATE EXTENSION pg_repack;
   ```

1. 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;
   ```

1. Conecte-se ao banco de dados usando o utilitário de cliente `pg_repack`. Use uma conta que tenha privilégios `rds_superuser`. Como exemplo, suponha que a função `rds_test` tenha os privilégios `rds_superuser`. A sintaxe a seguir realiza a `pg_repack` para tabelas completas, incluindo todos os índices da tabela no banco de dados `postgres`.

   ```
   pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U rds_test -k postgres
   ```
**nota**  
É necessário se conectar usando a opção -k. Não há suporte para a opção -a.

   A resposta do cliente `pg_repack` fornece 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"
   ```

1. A sintaxe a seguir recria uma única tabela `orders` incluindo índices no banco de dados `postgres`.

   ```
   pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U rds_test --table orders -k postgres
   ```

   A sintaxe a seguir recria somente os índices da tabela `orders` no banco de dados `postgres`.

   ```
   pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U rds_test --table orders --only-indexes -k postgres
   ```

## Monitorar a nova tabela durante a recriação
<a name="Appendix.PostgreSQL.CommonDBATasks.pg_repack.Monitoring"></a>
+ 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)` \$1 `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_repack` també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 `pgstattuple` para calcular a sobrecarga na tabela. Para ter mais informações, consulte [pgstattuple](https://www.postgresql.org/docs/current/pgstattuple.html).
+ 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's` em `pg_stat_all_tables` para monitorar as alterações aplicadas à nova tabela. `pg_stat_all_tables.n_live_tup` indica o número de registros pendentes a serem aplicados à nova tabela. Para ter mais informações, consulte [pg\$1stat\$1all\$1tables](https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ALL-TABLES-VIEW). 

  ```
  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_statements` para 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áusula `LIMIT` para 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.