sexta-feira, 1 de julho de 2011

PostgreSQL - Corrigindo tabela corrompida

Situação: Tabela com linhas corrompidas. 
Como identificar: Erro ao realizar o dump, select, delete na tabela. 


O problema é que quando isto ocorre o PostgreSQL informa que existe um erro e referencia o 'toast value', o que não é nada concreto para uma remoção por DELETE convencional. 


Exemplo:


ERROR: missing chunk number 0 for toast value 16983210 in pg_toast_939217
1532317



Então primeiro temos que identificar quais linhas desta tabela estão corrompidas, dai se utiliza o comando na console:


for ((i=0; i<TOTALROWS; i++ )); do psql -U postgres mydb -c "SELECT * FROM public.mytable LIMIT 1 offset $i" >/dev/null || echo $i; done


TOTALROWS: Altere o TOTALROWS pelo número total de linhas da tabelas depois de executar um ANALYZE. 
postgres: Role que executará a query, no caso o 'postgres' 
mydb: Sua database
mytable: A tabela alvo


Este comando varrerá a tabela linha a linha e pelo retorno você saberá quais linhas estão danificadas, segue exemplo de saída:


ERROR:  missing chunk number 0 for toast value 1269808 in pg_toast_93917
162558
ERROR:  missing chunk number 0 for toast value 1269810 in pg_toast_93917
162559


No caso acima sabemos agora que as linhas 162558 e 162559 estão corrompidas. 


Um DELETE não funcionará, não se iluda. Primeiro é necessário obter o CTID das linhas, pra quem quer ai vai a explicação do que é o CTID: http://www.postgresql.org/docs/8.4/static/datatype-oid.html


Então o próximo passo é obter este valor para ai sim fazer o DELETE, mas sugiro antes fazer um backup da tabela sem as linhas corrompidas:


CREATE TABLE mytable_bkp1 AS SELECT * FROM mytable LIMIT 162558;
CREATE TABLE mytable_bkp2 AS SELECT * FROM mytable OFFSET 162559;


Agora vamos ao CID:


SELECT CTID FROM mytable LIMIT 2 OFFSET 162558;


Agora sim, vamos remover as crianças e salvar o mundo:


DELETE FROM mytable WHERE CTID IN(SELECT CTID FROM mytable LIMIT 2 OFFSET 162558);


Tabela salva, todo mundo feliz. E sim, você perdeu as linhas deletadas!



Um comentário:

  1. E quando o erro parece ser causado apenas quando uma coluna específica está envolvida no comando SQL, alguma sugestão?
    Exemplo: Select * from tabela -> QL Error [XX000]: ERROR: missing chunk number 0 for toast value 184711 in pg_toast_2619
    Ai fui testando coluna por coluna no select: Select column1 from tabela, e etc..
    apenas quando uma coluna específica está envolvida que apresenta erro (para qualquer linha)

    ResponderExcluir