Banco de Dados · 6 de março de 2017 · 5 min de leitura

Recuperação no Nível de Blocos de Dados com RMAN

LAB: Recuperação no Nível de Blocos de Dados com RMAN.

Objetivo: abordar a recuperação de blocos de dados corrompidos usando RMAN.

(Se você não sabe o que é o Oracle RMAN, clique aqui.)

Alvo de recuperação: através do RMAN podemos recuperar blocos de dados que foram corrompidos, seja por falhas de hardware, SO, ou até mesmo problemas do próprio Oracle.

Erro: Mensagem “ORA-01578: blocos de dados Oracle danificado (arquivo núm. String, bloco núm. string)” significa que o Oracle tentou acessar algum bloco de dados corrompido em um datafile.

Itens para verificar:

  1. Quais blocos foram corrompidos;
  2. Natureza da corrupção;
  3. Analisar opções disponíveis para resolver o problema.

Opções para resolver o problema e suspender o aparecimento do erro ORA-01578:

  • Se for identificado que o segmento afetado é um índice de tabela, recriá-lo resolverá o problema;
  • Case o segmento seja uma tabela, verificar se existe uma cópia da tabela em outro lugar (bkp), de forma que seja possível reconstruir as linhas que foram afetadas;
  • Executar CREATE TABLE … AS SELECT … na tabela identificada com os blocos corrompidos de forma a isolar as linhas saudáveis das corrompidas;
  • Ignorar os blocos corrompidos fazendo uso de algumas procedures da package (FIX_CORRUPT_BLOCKS e SKIP_CORRUPT_BLOCKS);
  • Realizar uma recuperação do bloco corrompido (Bloco Media Recovery).

Para este LAB de hoje vamos explorar a recuperação através do Block Media Recovery.

$ rman target /
 
RMAN> backup tablespace TS_DADOS;

Após a realização do backup da tablespace vamos verificar a tabela T1 que está alocada dentro dela:

SELECT segment_name, tablespace_name, header_file, header_block, blocks, bytes FROM dba_segments WHERE segment_name=’T1’;
 
SELECT COUNT(*) FROM T1;

Agora vamos analisar através do ANALYZE a tabela com o objetivo de verificar se o segmento T1 está íntegro:

analyze table T1 validate structure;

Nesse momento vamos corromper alguns blocos do datafile ts_dados01.dbf. Como o bloco header do datafile é o 130, vamos corromper os blocos acima dele: 140, 240, 340, 440:

$ dd if=/dev/zero of=ts_dados01.dbf bs=8192 seek=140 conv=notrunc count=1
$ dd if=/dev/zero of= ts_dados01.dbf bs=8192 seek=240 conv=notrunc count=1
$ dd if=/dev/zero of= ts_dados01.dbf bs=8192 seek=340 conv=notrunc count=1
$ dd if=/dev/zero of= ts_dados01.dbf bs=8192 seek=440 conv=notrunc count=1

Para ter a garantia de que os dados serão lidos diretamente do datafile que alteramos e não do buffer cache na SGA, iremos forçar a limpeza do cache e realizar a execução de um select na tabela T1:

 alter system flush buffer_cache;

Agora veremos que tanto a instrução ANALYZE quanto o SELECT vão falhar e emitir o erro ORA-01578. Repare que a mensagem do erro vem acompanhada do número do arquivo de dados e o número do bloco afetado:

 SELECT count(*) from T1;

ERRO na linha 1:
ORA-01578: bloco de dados ORACLE danificado (arquivo núm. 58, bloco núm. 140)
ORA-01110: 58 do arquivo de dados: ‘/data/oracle/BD01/TBS_DATA_01.dbf’

 analyze table T1 validate structure;

ERRO na linha 1:
ORA-01578: bloco de dados ORACLE danificado (arquivo núm. 58, bloco núm. 140)
ORA-01110: 58 do arquivo de dados: ‘/data/oracle/BD01/TBS_DATA_01.dbf’

Para identificarmos qual o objeto foi afetado pela corrupção vamos executar um SELECT para selecionarmos os dados da view de dicionários de dados DBA_EXTENTS:

select segment_type,owner,segment_name from dba_extents where file_id = 4 and 131 between block_id and block_id+blocks -1;
SEGMENT_TYPE    OWNER     SEGMENT_NAME
 
————–  ——–  ————-
 
TABLE           PH        T1

Agora vamos fazer uma análise do tamanho padrão do bloco datafile ts_dados01.dbf para usar o DBVERIFY:

SELECT tablespace_name,block_size
 
from dba_tablespaces
 
where tablespace_name = ‘TS_DADOS’;
TABLESPACE_NAME                BLOCK_SIZE
 
—————————— ———-
 
TS_DADOS                          8192

$ dbv blocksize=8192 file=ts_dados01.dbf feedback=1000

**Page 140 is marked corrupt
**Corrupt block relative dba: 0x0e80008c (file 58, block 140)
Completely zero block found during dbv:

**Page 240 is marked corrupt
**Corrupt block relative dba: 0x0e8000f0 (file 58, block 240)
Completely zero block found during dbv:

**Page 340 is marked corrupt
**Corrupt block relative dba: 0x0e800154 (file 58, block 340)
Completely zero block found during dbv:

**Page 440 is marked corrupt
**Corrupt block relative dba: 0x0e8001b8 (file 58, block 440)
Completely zero block found during dbv:
Total Pages Marked Corrupt: 4

Percebemos então que os blocos corrompidos foram identificados e reportados pelo utilitário. Vamos agora utilizar o comando VALIDATE do RMAN para validar a tablespace TS_DADOS:

RMAN> validate tablespace TS_DADOS;
List of Datafiles
 
=================
 
File Status Marked Corrupt Empty Blocks Blocks Examined High SCN
 
—- —— ————– ———— ————— ———-
 
58   FAILED 0              236          1920            7840568913427
File Name: /u01/oradata/WINT/dados/ts_dados01.dbf
 
Block Type Blocks Failing Blocks Processed
 
———- ————– —————-
 
Data       0              525
 
Index      0              0
 
Other      4              148

Curiosidade: a partir do Oracle 11g, quando uma instrução SQL é abortada devido ao erro ORA-01578 pelo fato da mesma tentar acessar um bloco corrompido, o Oracle carrega as informações na view de desempenho V$DATABASE_BLOCK_CORRUPTION. Se preferir saber todos os blocos que estão corrompidos, podemos executar o comando VALIDATE DATABASE no RMAN. 

select * from v$database_block_corruption;
FILE#      BLOCK# BLOCKS CORRUPTION_CHANGE# CORRUPTION_TYPE
 
———- ————- —————— —————
 
58        140          1                  0 ALL ZERO
 
58        240          1                  0 ALL ZERO
 
58        340          1                  0 ALL ZERO
 
58        440        1                  0 ALL ZERO

Agora vamos usar um SELECT personalizado para retornar informações adicionais sobre os blocos corrompidos:

SELECT file#,
 
file_name,
 
c.tablespace_name,
 
block#,
 
corruption_change#,
 
corruption_type,
 
segment_type,
 
a.owner,
 
segment_name,
 
partition_name,
 
skip_corrupt
 
FROM dba_extents a, V$DATABASE_BLOCK_CORRUPTION b, dba_data_files c, dba_tables d
 
WHERE     b.file# = c.file_id
 
AND a.file_id = b.file#
 
AND a.segment_name=d.table_name
 
AND b.block# BETWEEN a.block_id AND a.block_id + a.blocks – 1;

Agora vamos confirmar se temos o backup da tablespace TS_DADOS:

RMAN> list backup of tablespace TS_DADOS;

Sabendo que temos o backup da TS_DADOS vamos realizar o RECOVERY do bloco 140 do datafile 4:

RMAN> blockrecover datafile 58 block 140;

**Disponível apenas para o Enterprise Edition

SQL> select * from v$database_block_corruption;

Se optarmos por recuperar todos os blocos listados na view V$DATABASE_BLOCK_CORRUPTION de uma vez basta executarmos o seguinte comando:

RMAN> blockrecover corruption list;

 **Disponível apenas para o Enterprise Edition

Agora só verificar mais uma vez a view citada acima e confirmar se os blocos com corrupção foram recuperados (não contendo nenhuma informação dentro dela).

Atualizado em 6 de março de 2017.

Esse problema aparece no seu ambiente?

Diagnóstico gratuito de infraestrutura e banco de dados — sem compromisso.

Falar com um especialista