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:
- Quais blocos foram corrompidos;
- Natureza da corrupção;
- 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).