Inhaltsverzeichnis
Database Block Recover - ORA-01578: ORACLE-Datenblock beschädigt
Erstellt 2014/07
Blockfehler treten selten auf, zum Beispiel in VM Umgebungen nach Stromausfällen.
Fehler
Ein RMan Backup läuft nicht durch und bricht mit dieser Fehlermeldung ab:
RMAN-00571: =========================================================== RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS =============== RMAN-00571: =========================================================== RMAN-03009: failure of backup command on ORA_DISK_1 channel at 06/13/2014 17:44:33 ORA-19566: exceeded limit of 0 corrupt blocks for file /oracle/GPI/oradata/user_data_01.dbf
Anlayse
Am einfachsten kann RMAn die Anlyse durchführen. Eine Analyse mit „dbv“ ( dbv file=oracle/GPI/oradata/user_data_01.dbf BLOCKSIZE=8192 userid=„/ as sysdba“ ) zeigt zwar die Fehler, hat aber in meinen Fall die Block Error View nicht mit Daten gefüllt
Mit RMAN die Datendatei analysieren mit „VALIDATE DATAFILE“:
RMAN> VALIDATE DATAFILE 4; Starting validate at 17-JUN-13 USING target DATABASE control file instead OF recovery catalog allocated channel: ORA_DISK_1 channel ORA_DISK_1: SID=157 device TYPE=DISK channel ORA_DISK_1: starting validation OF datafile channel ORA_DISK_1: specifying datafile(s) FOR validation INPUT datafile file NUMBER=00004 name=/oracle/GPI/oradata/user_data_01.dbf channel ORA_DISK_1: validation complete, elapsed TIME: 00:28:05 List OF Datafiles ================= File STATUS Marked Corrupt Empty Blocks Blocks Examined High SCN ---- ------ -------------- ------------ --------------- ---------- 5 FAILED 0 22536 4057345 515739533 File Name: /oracle/GPI/oradata/user_data_01.dbf Block TYPE Blocks Failing Blocks Processed ---------- -------------- ---------------- DATA 0 1812504 INDEX 0 1351035 Other 4784 891369 validate found one OR more corrupt blocks See trace file /oracle/GPI/diag/rdbms/GPI/GPIDB/trace/GPI_ora_17620.trc FOR details Finished validate at 17-JUN-13
In der Datenbank wird über RMAn die View v$database_block_corruption mit diesen Informationen gefüllt.
Über die View können nun die betroffenen Objekte ausgewertet werden:
SET linesize 120 pagesize 4000 recsep off COLUMN segment_name format a16 heading "Segment|Name" COLUMN tablespace_name format a16 heading "Tablespace|Name" COLUMN partition_name format a10 heading "Partition|Name" COLUMN owner format a14 COLUMN relative_fno format 9999 heading "File|No" COLUMN segment_type format a0 heading "Segment|Type" COLUMN file# format 9999 heading "File|Id" COLUMN defekt_range format a18 heading "defect|range" prompt CHECK OF the DATABASE has detected corrupt blocks SELECT COUNT(*) FROM v$database_block_corruption; prompt ... prompt CHECK which TABLES are affected prompt SELECT ext.owner , ext.segment_name , ext.segment_type , ext.relative_fno , ext.partition_name , ext.tablespace_name , blc.file# , blc.block# ||' for '||blc.blocks AS defekt_range FROM dba_extents ext , v$database_block_corruption blc WHERE ext.file_id = blc.file# AND blc.block# BETWEEN ext.block_id AND ext.block_id + ext.blocks - 1 /
Für die aktuellste Version see auch http://orapowershell.codeplex.com/SourceControl/latest#sql/tab_defekt_blocks.sql
RMAN Backup trotz defekten Blöcken anlegen - mit "set MAXCORRUPT" defekte Blöcke überspringen
RMAN> run { SET MAXCORRUPT FOR datafile 5 TO 10000; BACKUP AS COMPRESSED BACKUPSET DATABASE tag 'FULL_CORRUPT'; backup CURRENT controlfile; backup spfile; backup archivelog ALL; }
Die DB Blöcke aus einem alten Backup wieder einspielen
Mit „BLOCKRECOVER CORRUPTION LIST“ lassen sich alle Blöcke aus der v$database_block_corruption recovern. (Alternativ: BLOCKRECOVER mit Angabe der Block Nummer )
Datenbank ist im MOUNT Status gestartet!
Recover starten (im Beispiel war das letzte Backup ohne Fehler bereits 18 Tage alt) :
RMAN>BLOCKRECOVER CORRUPTION LIST RESTORE UNTIL TIME 'SYSDATE-18';
Die Blöcke werden nun aus dem alten Backup wieder hergestellt, pro Block geht RMAn über alle Archive und prüft ob für diesen Block Daten angewendet werden müssen, d.h. es kann etwas dauern.
Um die Performance zu steigern, kann es sich lohnen, zuerst alle Archive wieder mit RMAN auf die Platte zu legen um das wiederholte Auspacken aus dem Backup Sets zu vermeiden.
Prüfen ob alles geklappt hat
RMAN> VALIDATE DATAFILE 4; Starting validate at 27-JUN-13 allocated channel: ORA_DISK_1 channel ORA_DISK_1: SID=16 device TYPE=DISK channel ORA_DISK_1: starting validation OF datafile channel ORA_DISK_1: specifying datafile(s) FOR validation INPUT datafile file NUMBER=00005 name=/oracle/GPI/oradata/user_data_01.dbf channel ORA_DISK_1: validation complete, elapsed TIME: 00:00:55 List OF Datafiles ================= File STATUS Marked Corrupt Empty Blocks Blocks Examined High SCN ---- ------ -------------- ------------ --------------- ---------- 5 OK 0 22286 4057345 518197271 File Name: /oracle/GPI/oradata/user_data_01.dbf Block TYPE Blocks Failing Blocks Processed ---------- -------------- ---------------- DATA 0 1742666 INDEX 0 1289033 Other 0 1003359 Finished validate at 27-JUN-13
Was tun wenn kein Backup mehr exisiert?
Defekte Blöcke mit Event überspringen
Diese ist mir allerdings in einer Umgebung mit einer echten physikalischen Block Korruption nicht gelungen.
Defekte Blöcke überspringen:
ALTER system SET events=’10231 trace name context forever,level 10' ;
Neue Tabelle anlegen mit den Daten der defekten Tabelle:
CREATE TABLE new_table AS SELECT * FROM defect_table;
BESSER
- DDL der alten Tabelle ermittelten mit zum Beispiel ⇒ tab_ddl.sql Script
- Abhängige Objekte wie Indexe der Tabelle löschen
- Alte Tabelle umbenennen
- Neue Tabelle mit dem DDL anlegen
- Daten in die neue Tabelle kopieren
Daten in der neuen Tabelle prüfen und die alte Tabelle löschen:
DROP TABLE defect_table; RENAME new_tab TO defect_table;
Trace wieder abschalten:
ALTER system SET events ’10231 trace name context off’;
Defekte Blöcke mit SQL überspringen
Falls der Block nur einen Index betrifft, diesen einfach neu anlegen.
Nur die Blöcke lesen die nicht betroffen sind:
CREATE TABLE new_tab AS SELECT FROM defect_table WHERE rowid NOT IN(SELECT rowid FROM defect_table WHERE dbms_rowid.rowid_block_number(rowid)=:block ) /
Sind mehr als ein Block betroffen mit v$database_block_corruption entsprechend joinen! Block Range beachten!
DBMS_REPAIR
DB Objeckt mit DBMS_REPAIR reparieren siehe ⇒ http://docs.oracle.com/cd/B28359_01/server.111/b28310/repair004.htm#ADMIN11828 und http://www.oracle-base.com/articles/misc/detect-and-correct-corruption.php
Quellen
Oracle:
Web:
Verhindern: