!
!
!
!
!
!
!
!

Blocs corrompus en Oracle 7 (23/09/2003)
>Lors de la suppression d'un enregistrement dans une table, j'obtiens l'erreur oracle suivante :
>ORA-01578 : Oracle data block corrupted (file # 13, block # 54144)
>ORA-01110 : data file 13 :/chemin du datafile.dbf .
Oracle 7.2.3, Noarchivelog
Comment remédier ?
Dans ce cas, on ne peut PAS récupérer les lignes mauvaises, mais on peut sauvegarder les bonnes.

Comment?

  • Pour déterminer ou se trouve logiquement la corruption (dans CE cas):
select * from sys.dba_extents where file_id = 13 and 
54144 between block_id and (block_id + blocks - 1);
(filenum et blocknum sont affichés par ORA-0578). Cette requête donne le nom du segment et son type, etc. Si on les connaît deja, tant mieux ;-)

  • Pour recuperer les bonnes lignes, ajouter dans init.ora (et redémarrez l'instance)
event = "10231 trace name context forever"
Cet event permettra d'occulter les blocs pourris lors d'un scan.
  • Si c'est une table, faites un
create table tempo as select * from TABLEINITIALE;
drop table TABLEINITIALE;
create table TABLEINITIALE as select * from tempo;
(Ou un export, drop, import;)
  • Si c'est un index, droppez-le et recréez-le (en supprimant les contraintes, éventuellement)
  • Si c'est un rollback, droppez-le et recréez-le.
  • Si c'est un snapshot, droppez-le et recréez-le.
  • Remettez les contraintes, index, etc
  • Enlever l'event dans init.ora (et redémarrez l'instance)
Si plusieurs tables, index, sont atteints, réitérez :-)

Oracle en général (15/03/2004)
Qui n’a pas rencontré, au moins une fois, des blocs corrompus, qui ne s’est pas posé la question depuis quand existent-ils dans la base ? Plusieurs causes peuvent déterminer la corruption des blocs : interface d’entrée/sortie endommagée ou boguée (par exemple contrôleur disque défectueux), entrées/sorties OS incomplètes à cause d’un problème de cache, logiciels de réparation de disque (qui survient au boot suivant après l’écran bleu ?), mémoire défectueuse, etc.
Un bloc est écrit de manière binaire. ORACLE estime qu’un bloc est corrompu quand il n’est plus conforme à ce format. La vérification de cette conformité, présentée dans la première partie du livre, se fait d’habitude dans les couches supérieures du cache. Rappelons-nous qu’un bloc dans le cache contient des informations sur la version du bloc, les transactions le concernant et une information de checksum (non utilisée en standard afin de ne pas alourdir le traitement). Si une incohérence du bloc est détectée, en fonction de sa gravité et de la couche du noyau où elle a été découverte, le bloc est dit ‘media corrupt’ ou ‘software corrupt’.
Généralement, les erreurs ORA-1578 ou ORA-600 [3374] signalent la présence d’un ou plusieurs blocs corrompus. Nous pouvons dépister ces blocs en appliquant diverses méthodes, plus ou moins astucieuses :
Analyze table table_name validate structure cascade
Cette commande vérifie chaque bloc au niveau du cache et plus haut. Les index sont également analysés grâce à cet ordre.
Utiliser DB_VERIFY
DB_VERIFY est un utilitaire qui contrôle la cohérence physique des fichiers ORACLE. Les blocs de la base sont montés dans la SGA et les vérifications se font au niveau du cache. Il est utile, également, pour vérifier que les fichiers sauvegardés pourront être utilisés lors d’une restauration. Il accepte quelques paramètres dont un, non négligeable, est la taille du bloc. Il porte différents noms en fonction de la plate-forme OS. Vous pouvez vérifier les fichiers des données ou les fichiers redo log archivés.
Veillez à appliquer DB_VERIFY avec l’instance arrêtée, sinon …

Ses paramètres possibles sont affichés avec la commande :
Db_verify help=yes
Bien que vous n’êtes pas tenus de donner la plage de blocs à vérifier pour des fichiers OS (elle est obligatoire pour les raw devices), une bonne habitude est de l’indiquer systématiquement à DB_VERIFY !
Select bytes from v$datafile where name = ‘fichier’;
Select value from v$parameter where name = ‘db_block_size’;
Dbverf file=fichier, end=…
Checksum des blocs
ORACLE prévoit, par son architecture, la possibilité de marquer pour chaque bloc son checksum dans le bloc lui-même. L’écriture et l’analyse du checksum alourdissent d'environ 10% à 20% la charge globale d’ORACLE, mais l'analyse garantit l'alerte immédiate lors d’une non concordance. Les checksums sont calculés par DBWR et DIRECT LOADER lors de l’écriture du bloc et sont lus par les process serveurs. Le calcul et la vérification du checksum sont provoqués par les paramètres LOG_BLOCK_CHECKSUM pour les fichiers redo log et DB_BLOCK_CHECKSUM pour les fichiers de données.
Le paramètre _DB_BLOCK_CACHE_PROTECT (mis à TRUE), dans init.ora, renforce la protection du cache layer. Si jamais un bloc est corrompu dans le cache, il ne sera pas écrit sur le disque (globalement vous aurez un ORA-600 minimum ;-))
Dans la même plage de vérifications, nous disposons de plusieurs events pour vérifier la corruption des blocs. Ces events provoquent une corruption des blocs lors de la détection des erreurs :
alter session set events '102xx trace name context forever, level 10';
La réparation des blocs corrompus
En réalité, la réparation n’en est pas une : il s’agit plutôt d’une restauration ou d’un ensemble d’actions qui passe, presque systématiquement, par la destruction des objets (contenant les blocs corrompus leur recréation et leur repopulation.
Avant de procéder à une quelconque restauration , si vous en avez la possibilité, vous devriez analyser l’ampleur des dégâts en puisant toutes les informations des fichiers traces (ORACLE et OS). Une fois, les problèmes OS résolus, vous pouvez vous attaquer à la restauration. Votre objectif est presque atteint si vous arrivez à déterminer le numéro du fichier qui contient le bloc corrompu (i) et l’identifiant de ce bloc (j).
Déterminer l’objet qui contient le bloc endommagé :
SELECT owner, segment_name, segment_type
FROM dba_extents
WHERE file_id = i
AND j BETWEEN block_id AND block_id + blocks - 1;
Si le segment en cause est un index, trouver la table qu’il indexe :
SELECT table_owner, table_name
FROM dba_indexes
WHERE index_name = 'segment_name';
Si le segment en cause est un cluster, trouver la table (ou les tables) concernée :
SELECT owner, table_name
FROM dba_tables
WHERE cluster_name = 'segment_name';
Si le segment est une table, noter son nom et son proprietaire.
Passez l’ANALYZE plusieurs fois pour vérifier que vous n’êtes pas devant un faux problème.
Pour un index ou une table :
ANALYZE TABLE owner.tablename VALIDATE STRUCTURE CASCADE;
Pour un cluster :
ANALYZE CLUSTER owner.clustername VALIDATE STRUCTURE CASCADE;
Si les problèmes sont dus à un contrôleur défectueux ou à un disque, déplacer le fichier en cause sur un autre support.
Restauration en mode ARCHIVELOG
Mettre le fichier offline, le restaurer (sur un disque correct), le renommer, le recouvrir, le mettre online.
Restauration en mode NOARCHIVELOG
Restaurer le fichier (sur un disque correct), le renommer, le recouvrir, le mettre online.
Vous ne pouvez pas mettre un fichier offline en mode noarchivelog !

Quand la restauration est achevée, réanalyser l’objet initialement endommagé. Rien ne prouve que le bloc était corrompu hier, avant-hier, etc, mais il n’avait pas été utilisé après sa corruption. Ces étapes devraient être exécutées pour tous les fichiers qui contiennent des blocs abimés.
Si le problème persiste, préparons nous pour la mauvaise nouvelle : au mieux, nous pouvons espérer récupérer les données qui ne sont pas contenues dans les blocs corrompus ! Dans cette étape, pensons à l’économie de temps et d’énergie réalisée si nous supprimons un index et nous le recréons. Si nous avons un export de confiance, utilisons-le. Si nous nous approchons de la réalité ? en (re)passant deux ou trois batch, faisons-le !
Pour récupérer les données, si l’on connaît les blocs corrompus, nous pouvons extraire les données en évitant les identifiants de lignes (rowids) des blocs corrompus :
CREATE TABLE recup AS SELECT * FROM corrupt_table WHERE 1 = 2;
INSERT INTO recup SELECT /*+ ROWID(corrupt_table) */ * FROM corrupt_table
WHERE rowid <= 'low_rowid_of_corrupt_block';
INSERT INTO recup SELECT /*+ ROWID(corrupt_table) */ * FROM corrupt_table
WHERE rowid >= 'high_rowid_of_corrupt_block';
Inutile de vous dire que les cas de corruption d’un seul bloc sont rares, vous aurez à gérer la liste complète et implicitement une liste complexe d’inégalités.
L’utilisation de l’event 10231 permet de sélectionner les données autour des blocs corrompus. (ORACLE occulte les blocs corrompus lors d’un full table scan pendant l’utilisation de cet event).
event="10231 trace name context forever, level 10"
L’event 10233 est similaire à l’event 10231, mais il fonctionne avec les index (en range scan). Malheureusement, les données des blocs corrompus seront perdues !
Event But Vérification des blocs de données. Vérification des blocs d’index. Vérification des blocs de cluster. Vérifie les informations en fet$/uset$ pour toute corruption.

Copyright © 1998-2002 Radu Caulea, TAFORA MAJ 06/11/2006 !
Commentaires et suggestions radu[CHEZ]tafora.fr