quinta-feira, 13 de outubro de 2016

Formatando um bloco corrompido que não faz parte de um segmento

Durante a execução de um backup full database(RMAN) obtive o erro ORA-19566 informando a identificação de blocos corrompidos em um datafile. 

ORA-19566: exceeded limit of 0 corrupt blocks for file /oradata01/oracle/orcl/indices/TBS_INDICES40.dbf

Abrindo o alertlog do banco de dados temos um detalhamento do ocorrido, onde aponta inclusive qual objeto utiliza este bloco.

Mon Oct 03 10:35:02 BRT 2016
Hex dump of (file 439, block 299712) in trace file /home/oracle/home/admin/orcl/udump/orcl_ora_25903.trc
Corrupt block relative dba: 0x6dc492c0 (file 439, block 299712)
Fractured block found during buffer read
Data in bad block:
 type: 6 format: 2 rdba: 0x6dc492c0
 last change scn: 0x0040.47e5f156 seq: 0x1 flg: 0x04
 spare1: 0x0 spare2: 0x0 spare3: 0x0
 consistency value in tail: 0x00c351d5
 check value in block header: 0xd7cb
 computed block checksum: 0x9ae3
Reread of rdba: 0x6dc492c0 (file 439, block 299712) found same corrupted data
Mon Oct 03 10:35:02 BRT 2016
Corrupt Block Found
         TSN = 25, TSNAME = TBS_INDICES
         RFN = 439, BLK = 299712, RDBA = 1841599168
         OBJN = 60476, OBJD = 60476, OBJECT = IDX_TEST_FK_I, SUBOBJECT =
         SEGMENT OWNER = PRD, SEGMENT TYPE = Index Segment
Após realizar o rebuild do indice, executei um DBV (DBVERIFY) sobre o arquivo de dados e além do bloco 299712, foram identificados mais 2 blocos corrompidos (299713 e 299714)

Para asber mais sobre o DBV, clique aqui.

Banco=orcl-> dbv file=/oradata01/oracle/orcl/indices/TBS_INDICES40.dbf

DBVERIFY: Release 10.2.0.5.0 - Production on Tue Oct 4 08:29:29 2016

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

DBVERIFY - Verification starting : FILE = /oradata01/oracle/orcl/indices/TBS_INDICES40.dbf
Page 299712 is influx - most likely media corrupt
Corrupt block relative dba: 0x6dc492c0 (file 439, block 299712)
Fractured block found during dbv:
Data in bad block:
 type: 6 format: 2 rdba: 0x6dc492c0
 last change scn: 0x0040.47e5f156 seq: 0x1 flg: 0x04
 spare1: 0x0 spare2: 0x0 spare3: 0x0
 consistency value in tail: 0x00c351d5
 check value in block header: 0xd7cb
 computed block checksum: 0x9ae3

Page 299713 is marked corrupt
Corrupt block relative dba: 0x6dc492c1 (file 439, block 299713)
Bad header found during dbv:
Data in bad block:
 type: 231 format: 2 rdba: 0x001bfcf8
 last change scn: 0x006c.3710b7ec seq: 0xb5 flg: 0x1c
 spare1: 0x19 spare2: 0x0 spare3: 0x65
 consistency value in tail: 0x3f8303ce
 check value in block header: 0x3903
 computed block checksum: 0x0

Page 299714 is marked corrupt
Corrupt block relative dba: 0x6dc492c2 (file 439, block 299714)
Bad header found during dbv:
Data in bad block:
 type: 231 format: 2 rdba: 0x001bfd08
 last change scn: 0x0048.3710b7ec seq: 0x6d flg: 0x6c
 spare1: 0x19 spare2: 0x0 spare3: 0x5301
 consistency value in tail: 0x94410601
 check value in block header: 0x1389
 computed block checksum: 0x4162



DBVERIFY - Verification complete

Total Pages Examined         : 408832
Total Pages Processed (Data) : 0
Total Pages Failing   (Data) : 0
Total Pages Processed (Index): 405595
Total Pages Failing   (Index): 0
Total Pages Processed (Other): 668
Total Pages Processed (Seg)  : 0
Total Pages Failing   (Seg)  : 0
Total Pages Empty            : 2566
Total Pages Marked Corrupt   : 3
Total Pages Influx           : 1
Highest block SCN            : 1749727541 (64.1749727541)
Voltei na base de dados e verifiquei se havia mais algum segmento utilizando estes blocos:

SQL> SELECT tablespace_name, segment_type, owner, segment_name FROM dba_extents WHERE file_id = 439 and 299712 between block_id AND block_id + blocks - 1 ;

no rows selected

SQL> SELECT tablespace_name, segment_type, owner, segment_name FROM dba_extents WHERE file_id = 439 and 299713 between block_id AND block_id + blocks - 1 ;

no rows selected

SQL> SELECT tablespace_name, segment_type, owner, segment_name FROM dba_extents WHERE file_id = 439 and 299714 between block_id AND block_id + blocks - 1 ;

no rows selected

Nenhum segmento identificado nestes blocos!

Pois bem, já que não temos nenhum segmento, precisamos formatar este blocos.

Primeiramente identificamos a qual tablespace pertence o arquivo de dados:

SQL>  select tablespace_name from dba_data_files where file_name='/oradata01/oracle/orcl/indices/TBS_INDICES40.dbf';

TABLESPACE_NAME
------------------------------
TBS_INDICES

Agora criamos uma tabela abaixo desta tablespace, como no exemplo a seguir:

create table prd.fix_corrupt ( 
n number, 
c varchar2(4000) 
) PCTFREE 95 tablespace TBS_INDICES;

Utilizei PCTFREE 95 para que posteriormente seja necessário a inserção de menos registros até chegarmos ao bloco corrompido. 

Criado a tabela, vamos criar uma trigger para abortar o processo se inserção quando o bloco corrompido for utilizado e nos informar em tela.

CREATE OR REPLACE TRIGGER corrupt_trigger 
  AFTER INSERT ON prd.fix_corrupt
  REFERENCING OLD AS p_old NEW AS new_p 
  FOR EACH ROW 
DECLARE 
  corrupt EXCEPTION; 
BEGIN 
  IF (dbms_rowid.rowid_block_number(:new_p.rowid)=299712)
 and (dbms_rowid.rowid_relative_fno(:new_p.rowid)=439) THEN 
     RAISE corrupt; 
  END IF; 
EXCEPTION 
  WHEN corrupt THEN 
     RAISE_APPLICATION_ERROR(-20000, 'Corrupt block has been formatted'); 
END; 
/

Na trigger informei rowid_relative_fno(:new_p.rowid)=439 que é meu file_id e o dbms_rowid.rowid_block_number(:new_p.rowid)=299712 que é meu bloco corrompido.

O próximo passo é identificar o tamanho do extent corrompido para que possamos alocá-lo, desta forma realizamos a seguinte consulta na dba_free_space informando o file_id e o numero do bloco, no meu caso 299712.

SQL> Select BYTES from dba_free_space where file_id=439 and 299712 between block_id and block_id + blocks -1;

     BYTES
----------
  67108864

Neste caso é 64K (67108864/1024/1024), assim é possivel alocar o extent da seguinte forma:

alter table prd.fix_corrupt
allocate extent (DATAFILE '/oradata01/oracle/orcl/indices/TBS_INDICES40.dbf' SIZE 64K);


Como não sabemos se existem muitos extents de 64K livres no datafile, podemos utilizar o seguinte loop para alocar os extents:

**Detalhe** 

Antes de executar o comando verificar o maxsize do datafile, ou seja, qual o tamanho maximo que o datafile pode atingir, pois se todos os extents lives tiverem o mesmo tamanho ele pode crescer o datafile até chegar a este limite.

SQL> select bytes/1024/1024, maxbytes/1024/1024 from dba_data_files where file_name='/oradata01/oracle/orcl/indices/TBS_INDICES40.dbf';

BYTES/1024/1024 MAXBYTES/1024/1024
--------------- ------------------
           3194               3500

Meu datafile neste momento tem 3.194 MB e pode chegar até 3.500 MB Executando o loop para alocar os extents:

SQL> BEGIN
for i in 1..1000000 loop
EXECUTE IMMEDIATE 'alter table prd.fix_corrupt allocate extent (DATAFILE '||'''/oradata01/oracle/orcl/indices/TBS_INDICES40.dbf''' ||'SIZE 64K) ';
end loop;
end ;
/  2    3    4    5    6
BEGIN
*
ERROR at line 1:
ORA-01653: unable to extend table PRD.FIX_CORRUPT by 128 in tablespace
TBS_INDICES
ORA-06512: at line 3

Como podemos ver acima ele alocou extents até estourar o datafile, vamos ver agora o tamanho.

SQL> select bytes/1024/1024, maxbytes/1024/1024 from dba_data_files where file_name='/oradata01/oracle/orcl/indices/TBS_INDICES40.dbf';

BYTES/1024/1024 MAXBYTES/1024/1024
--------------- ------------------
           3500               3500

Como ele estava com maxsize de 3500MB o datafile parou de crescer quando chegou a este valor, se ele fosse de 30G, por exemplo, possivelmente ele iria alocar toda esta área o que não seria necessário.. sempre observar este fator antes de executar o loop! se for necessário reduzir o maxsize e após as alocações voltar o valor antigo. 

Agora vamos verificar se os blocos estão sendo utilizados pela tabela criada:

SQL> set lines 200
SQL> col segment_name for a70
SQL> select segment_name, segment_type, owner from dba_extents where file_id = 439 and 299712 between block_id and block_id + blocks -1;

SEGMENT_NAME                                                           SEGMENT_TYPE       OWNER
---------------------------------------------------------------------- ------------------ ------------------------------
FIX_CORRUPT                                                            TABLE              PRD

SEGMENT_NAME                                                           SEGMENT_TYPE       OWNER
---------------------------------------------------------------------- ------------------ ------------------------------
FIX_CORRUPT                                                            TABLE              PRD

SQL> select segment_name, segment_type, owner from dba_extents where file_id = 439 and 299714 between block_id and block_id + blocks -1;

SEGMENT_NAME                                                           SEGMENT_TYPE       OWNER
---------------------------------------------------------------------- ------------------ ------------------------------
FIX_CORRUPT                                                            TABLE              PRD

Visto que os blocos listados como corrompidos estão sendo alocados pela tabela criada, vamos inserir registros até que o bloco seja preenchido e formatado. Para isto iremos utilizar um loop de inserção até que a mensagem gerada pela trigger seja exibida na tela:


Begin
  FOR i IN 1..1000000000 loop
    for j IN 1..1000 loop
      Insert into prd.fix_corrupt VALUES(i,'x');
    end loop;
    commit;
  END LOOP;
END; 
/

Begin
*
ERROR at line 1:
ORA-20000: Corrupt block has been formatted
ORA-06512: at "SYS.CORRUPT_TRIGGER", line 10
ORA-04088: error during execution of trigger 'SYS.CORRUPT_TRIGGER'
ORA-06512: at line 4

Agora executamos um novo DBV para verificar se todos os blocos foram formatados:

Banco=orcl-> dbv file=/oradata01/oracle/orcl/indices/TBS_INDICES40.dbf

DBVERIFY: Release 10.2.0.5.0 - Production on Tue Oct 4 09:31:26 2016

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

DBVERIFY - Verification starting : FILE = /oradata01/oracle/orcl/indices/TBS_INDICES40.dbf


DBVERIFY - Verification complete

Total Pages Examined         : 448000
Total Pages Processed (Data) : 80471
Total Pages Failing   (Data) : 0
Total Pages Processed (Index): 358990
Total Pages Failing   (Index): 0
Total Pages Processed (Other): 1068
Total Pages Processed (Seg)  : 0
Total Pages Failing   (Seg)  : 0
Total Pages Empty            : 7471
Total Pages Marked Corrupt   : 0
Total Pages Influx           : 0
Highest block SCN            : 1758325239 (64.1758325239)
Banco=orcl->

Estando o valor de "Total Pages Marked Corrupt" = 0 ficou tudo OK, caso ele ainda indique a presença de blocos corrompidos e sem segmentos basta recriar a trigger informando o novo bloco, reexecutar o insert e ao final o DBV até que o valor de blocos marcados como corrompidos seja 0.

Ao termino do processo remover a tabela criada:

SQL> drop table prd.fix_corrupt;

Table dropped.

Referência: 
https://docs.oracle.com/cd/B28359_01/backup.111/b28270/rcmvalid.htm
Postagem mais recente Postagem mais antiga Página inicial

0 comentários:

Postar um comentário

Translate

# ACE Program

#Oracle

#Oracle
Disclaimer: The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.

#Blog reconhecido

#ARTICULISTA

Marcadores

Postagens populares