Je travaillais récemment sur des corruptions de blocs de données et j'avais besoin de vider certains blocs de données pour vérifier leur contenu. J'ai dû balayer un article que j'ai écrit il y a longtemps et qui montrait comment faire cela. Ce qui suit est une partie de cet article :
Pour vider un bloc appartenant à une table, vous devez connaître le numéro de fichier et le numéro de bloc de ce bloc. Si vous connaissez déjà le numéro de dossier et le bloc, vous êtes prêt. Si vous ne connaissez pas le numéro de fichier et le bloc, vous pouvez interroger DBA_EXTENTS pour obtenir ces informations. Maintenant que nous savons quel fichier et quels blocs contiennent notre table, vidons un exemple de bloc de la table. Cela se fait comme suit :
ORA9I SQL> alter system dump datafile 3 block 10;
System altered.
Vous pouvez vider une plage de blocs avec la commande suivante :
ORA9I SQL> alter system dump datafile 3 block min 10 block max 12;
System altered.
Regardons maintenant le contenu du vidage d'un bloc.
Start dump data blocks tsn: 3 file#: 3 minblk 10 maxblk 10
buffer tsn: 3 rdba: 0x00c0000a (3/10)
scn: 0x0000.00046911 seq: 0x02 flg: 0x04 tail: 0x69110602
frmt: 0x02 chkval: 0x579d type: 0x06=trans data
Block header dump: 0x00c0000a
Object id on Block? Y
seg/obj: 0x6d9c csc: 0x00.46911 itc: 2 flg: O typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 xid: 0x0005.02f.0000010c uba: 0x00806f10.00ca.28 C--- 0 scn 0x0000.00046900
0x02 xid: 0x0003.01c.00000101 uba: 0x00800033.0099.04 C--- 0 scn 0x0000.00046906
C'est le début du vidage du bloc de données. La première ligne nous indique que nous vidons le fichier n° 3, en commençant par le bloc n° 10 (minblk) et en terminant par le bloc n° 10 (maxblk). Si nous avions vidé plus d'un bloc de données, ces valeurs représenteraient une plage. L'adresse relative du bloc de données (rdba) est 0x00c0000a. Pour plus d'informations sur le rdba, reportez-vous à une section ultérieure de ce document. A la fin de cette ligne, on peut voir entre parenthèses que le rdba correspond au fichier#3, bloc#10 (3/10).
La troisième ligne décrit le SCN du bloc de données. Dans notre cas, le SCN est 0x0000.00046911. La queue du bloc de données est composée des deux derniers octets du SCN (6911) auxquels sont ajoutés le type (06) et la séquence (02). Si la décomposition de la queue ne correspond pas à ces trois valeurs, alors le système sait que le bloc est incohérent et doit être récupéré. Bien que cette valeur de fin apparaisse au début du vidage de bloc, elle est physiquement stockée à la fin du bloc de données.
Le type de bloc apparaît sur la quatrième ligne. Certains des types valides correspondent au tableau suivant :
Type Meaning
0x02 undo block
0x06 table or index data block
0x0e undo segment header
0x10 data segment header block
0x17 bitmapped data segment header
Le message "ID d'objet sur bloc ?" La ligne nous indique si cet objet est ou non dans SYS.OBJ$. Depuis Oracle 6, cela devrait toujours être "Y". Si vous regardez la ligne suivante, la valeur seg/obj nous indique l'identifiant d'objet du segment (en hexadécimal). Dans notre exemple, il s'agit de 0x6d9c. Hex '6D9C' est '28060' en décimal. Nous pouvons vérifier qu'il s'agit de notre table avec la requête suivante :
ORA9I SQL> select owner,object_name from dba_objects
2 where object_id=28060;
OWNER OBJECT_NAME
---------- ------------------------------
PEASLAND EMP
Comme nous l'avions espéré, voici notre table.
La valeur csc est le numéro de modification du système de nettoyage. Cette valeur nous indique quand le nettoyage de bloc a été effectué sur ce bloc. Espérons qu'il corresponde au SCN du bloc de données. La valeur itc correspond au nombre de listes de transactions intéressées. Dans notre cas, il y a deux transactions intéressées par ce bloc. Ces transactions intéressées apparaissent à la fin de notre exemple. Nous pouvons voir l'identifiant de transaction (Xid) de ces deux transactions. Ces identifiants de transaction correspondent aux segments de restauration utilisés pour traiter nos transactions.
Le drapeau (flg) est soit "-" ou "O", utilisé pour indiquer si ce bloc est sur une liste libre. Si le bloc est sur une liste libre, le drapeau sera "0". S'il n'est pas sur une liste libre, alors le drapeau sera "-". Notre bloc en question est sur la liste libre.
Eh bien, c'était beaucoup d'informations et nous n'avons pas vraiment regardé trop de la décharge. Regardons la section suivante du vidage du bloc de données.
data_block_dump
===============
tsiz: 0x1fa0
hsiz: 0x2e
pbl: 0x024d015c
bdba: 0x00c0000a
flag=-------------
ntab=1
nrow=14
frre=9
fsbo=0x2e
fseo=0x1b18
avsp=0x1d8a
tosp=0x1d8a
0xe:pti[0] nrow=14 offs=0
0x12:pri[0] offs=0x1c30
0x14:pri[1] offs=0x1f4f
0x16:pri[2] offs=0x1f24
0x18:pri[3] offs=0x1efb
0x1a:pri[4] offs=0x1ece
0x1c:pri[5] offs=0x1ea5
0x1e:pri[6] offs=0x1e7c
0x20:pri[7] offs=0x1e54
0x22:pri[8] offs=0x1e2e
0x24:pri[9] sfll=13
0x26:pri[10] offs=0x1ca4
0x28:pri[11] offs=0x1cf1
0x2a:pri[12] offs=0x1b18
0x2c:pri[13] sfll=-1
La valeur tsiz nous indique la quantité d'espace disponible dans le bloc pour les données. Ici, nous obtenons '1fa0' qui se traduit par 8 096 octets d'espace utilisable. Le reste de notre bloc de 8 192 octets est utilisé pour les frais généraux tels que l'en-tête de bloc.
La valeur ntab nous montre combien de tables sont stockées dans ce bloc. À moins que ce bloc n'appartienne à un cluster, cette valeur sera "1". La valeur nrow nous indique combien de lignes de données sont stockées dans ce bloc. Notre bloc de données comporte 14 lignes de données.
À partir de l'adresse '0xe', nous obtenons un répertoire pour chaque ligne. Nous pouvons voir que la première ligne (entrée d'index zéro) commence à l'adresse de décalage vers le bloc '0x1c30'. Chacune des rangées de blocs découle d'ici. De cette façon, une ligne peut être trouvée très rapidement. N'oubliez pas qu'un ROWID est essentiellement un pointeur vers une ligne unique. Dans Oracle 8+, le ROWID est de la forme O.F.B.R (ou objectno,relativefno,blockno,rowno). Ainsi, lorsque le système pointe rapidement vers un bloc particulier dans un fichier particulier, le numéro de ligne pointe vers un emplacement de ce répertoire. Le répertoire pointe alors vers un emplacement spécifique dans le bloc. C'est le début de cette ligne.
Maintenant que nous avons une feuille de route pour notre bloc de données, examinons le reste du fichier de trace pour voir les lignes de données réelles dans le bloc.
block_row_dump:
tab 0, row 0, @0x1c30
tl: 39 fb: --H-FL-- lb: 0x0 cc: 8
col 0: [ 3] c2 4a 46
col 1: [ 5] 53 4d 49 54 48
col 2: [ 5] 43 4c 45 52 4b
col 3: [ 3] c2 50 03
col 4: [ 7] 77 b4 0c 11 01 01 01
col 5: [ 3] c2 09 19
col 6: *NULL*
col 7: [ 2] c1 15
Les données de ligne réelles commencent par la phrase "block_row_dump :". Ensuite, une ligne de données est donnée. Je n'ai montré qu'une seule ligne de données ici, car le reste est similaire. Nous pouvons voir que cette ligne appartient à la table '0' (onglet) de notre cluster. Puisqu'il n'y a pas de cluster dans notre exemple, nous n'avons pas plus d'une table donc cette valeur sera zéro. Nous pouvons également voir qu'il s'agit de la ligne '0' et que l'adresse de cette ligne est donnée. Cette adresse doit correspondre à notre feuille de route indiquée ci-dessus.
La valeur 'tl' nous donne le nombre total d'octets pour cette ligne, y compris toute surcharge. Nous pouvons voir que cette ligne occupe 39 octets. La valeur 'cc' nous donne un nombre de colonnes. Nous avons huit colonnes dans cette ligne. Cela peut facilement être vérifié en faisant un DESCRIBE sur la table et en comptant les colonnes, ou en interrogeant USER_TAB_COLUMNS.
La valeur 'fb' nous donne des drapeaux sur la ligne. « H » signifie que nous avons la tête de la rangée. « F » signifie que nous avons le premier morceau de la rangée. « L » signifie que nous avons également le dernier morceau de la rangée. Comme il s'agit de la première et de la dernière pièce de la rangée, la rangée n'est pas chaînée. Comme il s'agit également de l'en-tête de la ligne, la ligne n'a pas été migrée.
Le reste des informations de la ligne correspond aux données de chaque colonne. Par exemple, dans la colonne 1, nous avons les codes de caractères ASCII suivants, "53 4d 49 54 48". Un rapide coup d'œil à un tableau de conversion ASCII nous dira que ces caractères sont "SMITH". Si vous connaissez l'exemple de table EMP, vous savez que SMITH est l'un de nos employés. Notez que la colonne 6 est NULL. La colonne 4 est la colonne HIREDATE. Il s'agit d'un type de données DATE. À partir de ce bloc, vous pouvez facilement vérifier que le type de données DATE nécessite sept octets de stockage. La colonne 0 contient un nombre. Les trois octets ici sont la représentation de ce nombre.