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

06 mar

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

Design sem nome (2)

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.

 

[sql]
$ rman target /
RMAN> backup tablespace TS_DADOS;
[/sql]

 

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

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

 

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

[sql]
analyze table T1 validate structure;
[/sql]

 

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:

[sql] alter system flush buffer_cache;[/sql]

 

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:

[sql] SELECT count(*) from T1;[/sql]

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'

[sql] analyze table T1 validate structure;[/sql]

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:

[sql]
select segment_type,owner,segment_name from dba_extents where file_id = 4 and 131 between block_id and block_id+blocks -1;
[/sql]

[text]
SEGMENT_TYPE    OWNER     SEGMENT_NAME
--------------  --------  -------------
TABLE           PH        T1
[/text]

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

[sql]SELECT tablespace_name,block_size
from dba_tablespaces
where tablespace_name = 'TS_DADOS';
[/sql]

[plain]
TABLESPACE_NAME                BLOCK_SIZE
------------------------------ ----------
TS_DADOS                          8192
[/plain]

$ 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:

[sql]
RMAN> validate tablespace TS_DADOS;
[/sql]

[plain]
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
[/plain]

 

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. 

[sql]
select * from v$database_block_corruption;
[/sql]

[plain]
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
[/plain]

 

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

[sql]
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;
[/sql]

 

Agora vamos confirmar se temos o backup da tablespace TS_DADOS:

[sql]
RMAN> list backup of tablespace TS_DADOS;
[/sql]

 

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

[sql]RMAN> blockrecover datafile 58 block 140;[/sql]

**Disponível apenas para o Enterprise Edition

[sql]
SQL> select * from v$database_block_corruption;
[/sql]

 

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

[sql]
RMAN> blockrecover corruption list;
[/sql]

 

 **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).