quinta-feira, 5 de abril de 2012

Corrupção física e lógica no Oracle


Este artigo relata um fato vivido recentemente em uma base de dados no mundo real.

Primeiro vamos aos conceitos:

O que é uma corrupção física?

Um bloco pode estar corrompido se o “CHECKSUM” estiver inválido. E quando isso pode ocorrer?

Quando o cabeçalho do bloco estiver inválido - ocorre início do bloco está corrompido com valores inválidos.

Quando o bloco estiver incompleto – ocorre quando as informações do cabeçalho do bloco não correspondem com o restante do bloco (conhecido também como cauda de bloco).

Quando CHECKSUM estiver inválido – o  (CHECKSUM) é calculado pelo processo (DBWR) ou pelo processo (direct loader) antes de gravar o bloco do disco e armazenar o cabeçalho do bloco.

O parâmetro  DB_BLOCK_CHECKSUM pode ser usado para identificar se o bloco foi alterado por algo externo ao banco de dados e também para depois que o bloco foi gravado pela última vez pelo banco de dados. Toda vez que o bloco é lido e se o parâmetro DB_BLOCK_CHECKSUM estiver diferente de FALSE, o banco de dados calcula o CHECKSUM e compara a informação armazenada no cabeçalho do bloco.

Blocos deslocados – ocorrec quando o banco de dados Oracle detecta que o conteúdo do bloco a ser lido pertence a um bloco diferente e o CHECKSUM é válido. A corrupção de blocos físicos, normalmente são relatados como erros ORA-1578 e a descrição detalhada da corrupção é gravada no arquivo do “alert.log”.

O que é uma corrupção lógica?


Quando o bloco contém a verificação do CHECKSUM válida e a estruturado início do bloco está corrompida (o conteúdo do bloco está corrompido).

Corrupções lógicas não são normalmente gravadas no alert.log. O utilitário DBVerify apresenta os blocos que estão logicamente danificados no bloco.

Quando o parâmetro DB_BLOCK_CHECKING está habilitado, ele grava o erro interno ORA-600 [kddummy_blkchk].

Se o parâmetro DB_BLOCK_CHECKING estiver habilitado e o bloco já estiver logicamente corrompido no disco, a próxima atualização do bloco irá marcar o bloco como “Soft Corrupt” e futuras leituras deste bloco irão produzir o erro ORA-1578. Nesse caso o utilitário DBVerify apresenta a corrupção com o erro "DBV-200: Block, dba, already marked corrupted".

Como identificar os segmentos corrompidos no banco de dados?

Para identificar tanto o dano físico como lógico pode usar:

1.   Utilitário RMAN (Recovery Manager) ou;

2.   Utilitário DB Verify – DBV

§  Utilizando o RMAN o paralelismo torna a validação mais rápida, porque utiliza vários canais.

§  Por “default” os backups via RMAN (não possuem a opção de verificação lógica) só existe a detecção de corrupções de bloco físico. 

Abaixo é apresentado o comando que verifica o banco de dados completo para ambas corrupções (lógica ou física) sem realmente executar  uma cópia de segurança

RMAN> configure device type disk parallelism 4;
RMAN> backup validate check logical database;

ou

RMAN> run {
allocate channel diskl1 type disk;
allocate channel disk2 type disk;
allocate channel disk3 type disk;
allocate channel disk4 type disk;
backup validate check logical database;
}


Como identificar corrupção física ou lógica utilizando o utilitário DBVerify?

O utilitário DBVERIFY identifica corrupções físicas e lógicas, porém esse utilitário não pode ser executado no banco de dados inteiro utilizando somente um único comando. Para executá-lo não é necessário conexão com o banco de dados.

Deve-se indicar cada “datafile”, como no exemplo abaixo:

$ dbv file=[caminho+nome_do_datafile]
      blocksize = [tamanho_do_bloco_do_banco_de_dados]


Qual é o melhor? RMAN ou DBV?

  •   O RMAN pode ser executado com a opção de paralelismo, tornando-o mais rápido que o DBV que não pode ser executado em paralelo.
  •   O DBV verifica a existência de blocos vazios. Então levará mais tempo para fazer a varredura de arquivo de dados inteiro.
  •   Na versão do Oracle 10g o RMAN não pode marcar blocos com extensões livres quando estejam configuradas em LMT (Locally Managed Tablespaces).
  •   Na versão do Oracle 11g o RMAN verifica as extensões usadas e livres.
     RMAN> VALIDATE DATAFILE 1 BLOCK 10 to 100;. 

DBV> start=10 end=100

  • O RMAN mantém as informações de corrupção no arquivo de control file (nas visões: v$ database_block_corruption e  v$ backup_corruption). O  DBV não grava as informações de corrupção. As informações podem ser vistas utilizando a consulta abaixo.

    Select * from v$database_block_corruption;

  •  O RMAN não grava detalhes de corrupção como o que exatamente está corrompido em um bloco relatado como uma lógica bloco corrompido.O DBV relata os detalhes de corrupção na tela ou em um arquivo de log.
  • O DBV pode digitalizar blocos com um SCN mais elevado do que um determinado SCN.
  • O DBV não precisa de uma conexão com o banco de dados.

select * from dba_extents
 where file_id = &DATA_FILE_ID
   and &CORRUPTED_BLOCK_ID 
    between block_id AND block_id + blocks - 1;

ou

SELECT e.owner, e.segment_type, e.segment_name, e.partition_name, c.file#
     , greatest(e.block_id, c.block#) corr_start_block#
     , least(e.block_id+e.blocks-1, c.block#+c.blocks-1) corr_end_block#
     , least(e.block_id+e.blocks-1, c.block#+c.blocks-1)
       - greatest(e.block_id, c.block#) + 1 blocks_corrupted
     , null description
  FROM dba_extents e, v$database_block_corruption c
 WHERE e.file_id = c.file#
   AND e.block_id <= c.block# + c.blocks - 1
   AND e.block_id + e.blocks - 1 >= c.block#
UNION
SELECT s.owner, s.segment_type, s.segment_name, s.partition_name, c.file#
     , header_block corr_start_block#
     , header_block corr_end_block#
     , 1 blocks_corrupted
     , 'Segment Header' description
  FROM dba_segments s, v$database_block_corruption c
 WHERE s.header_file = c.file#
   AND s.header_block between c.block# and c.block# + c.blocks - 1
UNION
SELECT null owner, null segment_type, null segment_name, null partition_name, c.file#
     , greatest(f.block_id, c.block#) corr_start_block#
     , least(f.block_id+f.blocks-1, c.block#+c.blocks-1) corr_end_block#
     , least(f.block_id+f.blocks-1, c.block#+c.blocks-1)
       - greatest(f.block_id, c.block#) + 1 blocks_corrupted
     , 'Free Block' description
  FROM dba_free_space f, v$database_block_corruption c
 WHERE f.file_id = c.file#
   AND f.block_id <= c.block# + c.blocks - 1
   AND f.block_id + f.blocks - 1 >= c.block#
order by file#, corr_start_block#;




Rubens Oliveira
DBA Oracle Consultor
olivert.dba@consultant.com