Seiten

Dienstag, 24. September 2013

Korrupte Blöcke bekämpfen mit DBMS_REPAIR

Eine plötzliche Blockcorruption ist keine angenehme Überraschung. Wenn sich die Malaise nicht per Recovery beheben lässt, kann dbms_repair helfen.
Also.
Der Admin stellt auf einmal fest, dass Tabelle xyz_table dank einer blockcorruption nicht komplett lesbar ist oder sich nicht mit dpexp/exp exportieren lässt. (z.B.: ORA-31693: ...ORA-02354: ...ORA-00600: internal error code, arguments: [25027], [4], [394435]...)
Ein Recovery wird verworfen, da die Koruption schon zu lange existiert und andere Daten verloren gingen.
Die Lösung ist DBMS_REPAIR:
Zunächst werden die korrupten Blöcke mit dbms_repair markiert, damit die betroffene Tabelle wieder komplett gelesen/exportiert werden kann.
DBMS_REPAIR benötigt dafür eine Repairtabelle. Diese legt man hiermit an:
SET SERVEROUTPUT ON
DECLARE num_corrupt INT;
BEGIN

num_corrupt := 0;

DBMS_REPAIR.CHECK_OBJECT (
     SCHEMA_NAME => 'BEISPIEL',
     OBJECT_NAME => 'XYZ_TABLE',
     REPAIR_TABLE_NAME => 'REPAIR_TABLE',
     CORRUPT_COUNT =>  num_corrupt);
DBMS_OUTPUT.PUT_LINE('number corrupt: ' || TO_CHAR (num_corrupt));

END;
/

Anschließend jagt man DBMS_REPAIR über die kaputte Tabelle:

SET SERVEROUTPUT ON
DECLARE num_corrupt INT;
BEGIN

num_corrupt := 0;

DBMS_REPAIR.CHECK_OBJECT (
     SCHEMA_NAME => 'BEISPIEL',
     OBJECT_NAME => 'XYZ_TABLE',
     REPAIR_TABLE_NAME => 'REPAIR_TABLE',
     CORRUPT_COUNT =>  num_corrupt);
DBMS_OUTPUT.PUT_LINE('number corrupt: ' || TO_CHAR (num_corrupt));

END;
/

Jetzt kann man in der Repairtabelle nachsehen, was im Argen liegt:
SELECT OBJECT_ID, TABLESPACE_ID tsid,
   RELATIVE_FILE_ID fileid, BLOCK_ID,
   CORRUPT_TYPE, CORRUPT_DESCRIPTION, REPAIR_DESCRIPTION
FROM REPAIR_TABLE;

Hier die ausführliche CORRUPT_DESCRIPTION:

Block Checking: DBA = 16780739, Block Type = KTB-managed data block
data header at 0xf25ec07c
kdbchk: row locked by non-existent transaction
        table=0   slot=1
        lockid=6   ktbbhitc=3

Jetzt, wo man weiß, welche Block-ID – in diesem Fall die 3523 – betroffen ist, kann man mit diesem Select sogar den Inhalt finden und anzeigen:
SELECT * FROM XYZ_TABLE
WHERE DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid) = 3523

Das sieht wirklich kaputt aus... aber mit ein wenig Kenntnis des Datenmodells und der Anwendung weiß man jetzt vielleicht sogar, wie man an die korrekten Daten kommt.
Anschließend kann die Tabelle korrigiert werden - z.B. mittels DBMS_REPAIR.FIX_CORRUPT_BLOCKS().

1 Kommentar:

  1. Im ersten Code-Segment sollte es wohl heißen:

    BEGIN
    DBMS_REPAIR.ADMIN_TABLES (
    TABLE_NAME => 'REPAIR_TABLE',
    TABLE_TYPE => dbms_repair.repair_table,
    ACTION => dbms_repair.create_action,
    TABLESPACE => 'USER');
    END;
    /


    *lg*

    Thomas Rosenberg

    AntwortenLöschen