Como consertei uma tabela do postgres

Estou escrevendo este post sobre um erro de chunk ausente em uma tabela postgres que estava falhando meus backups diários. Consegui resolver e quero apresentar o método que usei caso seja útil para alguém que encontre esse problema. De forma alguma este é um guia ou instruções profissionais sobre como resolver corretamente erros de chunk ausente no postgres, pois não sou um especialista e fiz isso sem ter muito conhecimento, mas funcionou no final.

O erro que eu estava recebendo durante os backups:

pg_dump: error: Dumping the contents of table "stylesheet_cache" failed: PQgetResult() failed.
pg_dump: error: Error message from server: ERROR:  missing chunk number 0 for toast value 1903804 in pg_toast_22663
pg_dump: error: The command was: COPY public.stylesheet_cache (id, target, digest, content, created_at, updated_at, theme_id, source_map) TO stdout;

Então o problema estava na tabela stylesheet_cache, ERRO: missing chunk number 0 for toast value 1903804 in pg_toast_22663.

Estou usando Discourse no Docker, então aqui está o que eu fiz:

ssh into the server
cd /path/to/discourse
./launcher rebuild app
su postgres -c "psql discourse"

Assim que entrei no postgres, tentei REINDEXAR a tabela na esperança de que isso resolvesse o problema.

discourse=# select reltoastrelid::regclass from pg_class where relname = 'stylesheet_cache';
      reltoastrelid      
-------------------------
 pg_toast.pg_toast_18396
(1 row)
REINDEX table stylesheet_cache;
REINDEX table pg_toast.pg_toast_18396;
VACUUM analyze stylesheet_cache;

Tentei fazer o backup novamente, ainda falhou, então tive que continuar procurando a corrupção.

Calculei o número total de linhas na minha tabela com:

select count(*) from stylesheet_cache;

Obtive uma contagem de 2260 linhas.

Fui procurar a linha exata que estava corrompida e excluí-la, de alguma forma presumi que stylesheet_cache não é algo que possa realmente quebrar todo o meu banco de dados. Como mencionei, não sou um especialista, então talvez eu tenha dado um salto de fé muito grande, então tenha cuidado ao fazer isso, pois você pode estragar seu banco de dados.

Usei as consultas LIMIT e OFFSET para encontrar as linhas corrompidas:

select * from stylesheet_cache order by id limit 100 offset 0;

Brinquei com o offset e o limit até obter o erro Missing chunk… e então reduzi para LIMIT 1 e fiz o offset da linha que estava corrompida. No meu caso, havia 5 linhas corrompidas.

Você poderia usar um script sh para encontrar a linha com menos esforço, eu fui pelo caminho manual que levou algum tempo, mas você poderia usar isso:

#!/bin/sh
j=0
while [ $j -lt 2260 ]
do
  psql -U postgres -d discourse -c "SELECT * FROM stylesheet_cache LIMIT 1 offset $j" >/dev/null || echo $j
  j=$(($j+1))
done

Fui procurar o id da linha corrompida com o seguinte comando:

select id from stylesheet_cache order by id limit 1 offset 450;

id

----

11498

Então o id da minha linha corrompida era 11498.
Excluí a linha com:

delete from stylesheet_cache where id = 11498;

Após excluir as linhas corrompidas, fui REINDEXAR novamente:

REINDEX table stylesheet_cache;
REINDEX table pg_toast.pg_toast_40948;
VACUUM analyze stylesheet_cache;

E tentei fazer o backup novamente, desta vez funcionou. Eu me guiei usando estas instruções de recuperação do postgres: Postgres error: Missing chunk 0 for toast value in pg_toast · GitHub

AVISO LEGAL: esta não é uma opinião de especialista, portanto, proceda com cautela se você tiver corrupções de chunk ausente semelhantes e estiver tentando corrigi-las.

3 curtidas