===== 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=== Darauf achten, dass die alten RMAN Backup NICHT gelöscht werden! 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 ) Alle Archive bis zum aktuellen Zeitpunkt müssen noch zur Verfügung stehen! **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 Ein neues Backup anlegen und dann die Archive und alten Backups aufräumen! ==== 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 => [[http://orapowershell.codeplex.com/SourceControl/latest#sql/tab_ddl.sql|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: * http://docs.oracle.com/cd/E11882_01/backup.112/e10642/rcmblock.htm#BRADV89781 * http://docs.oracle.com/cd/B19306_01/server.102/b14237/dynviews_1074.htm Web: * http://www.oracle-base.com/articles/misc/detect-and-correct-corruption.ph Verhindern: * https://blog.dbi-services.com/protecting-an-oracle-database-from-block-corruption/