Jeg arbejdede for nylig på nogle datablokkorruptioner, og jeg var nødt til at dumpe nogle datablokke for at bekræfte indholdet. Jeg var nødt til at børste et papir af, som jeg skrev for længe siden, og som viste, hvordan man gør dette. Det følgende er en del af det papir:
For at dumpe en blok, der tilhører en tabel, skal du kende filnummeret og bloknummeret for den pågældende blok. Hvis du allerede kender filnummeret og blokeringen, så er du klar. Hvis du ikke kender filnummeret og blokeringen, kan du forespørge DBA_EXTENTS om disse oplysninger. Nu hvor vi ved, hvilken fil og hvilke blokke der holder vores bord, lad os dumpe en prøveblok af bordet. Dette gøres på følgende måde:
ORA9I SQL> ændre systemdump datafil 3 blok 10;
System ændret.
Du kan dumpe en række blokke med følgende kommando:
ORA9I SQL> ændre system dump datafil 3 blok min 10 blok max 12;
System ændret.
Lad os nu se på indholdet af at dumpe én blok.
Start dump datablokke tsn:3 fil#:3 minblk 10 maxblk 10
buffer tsn:3 rdba:0x00c0000a (3/10)
scn:0x0000.00046911 seq:4g tail:x :0x69110602
frmt:0x02 chkval:0x579d type:0x06=trans data
Blok header dump:0x00c0000a
Objekt id på blok? Y
seg/obj:0x6d9c csc:0x00.46911 itc:2 flg:O type: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.000469000 /3000469000 <3 00000101 uba:0x00800033.0099.04 C--- 0 scn 0x0000.00046906
Dette er begyndelsen på datablokdumpet. Den første linje fortæller os, at vi dumper fil#3, starter ved blok#10 (minblk) og slutter med blok#10 (maxblk). Hvis vi havde dumpet mere end én datablok, ville disse værdier repræsentere et interval. Den relative datablokadresse (rdba) er 0x00c0000a. For mere information om rdba, se et senere afsnit i dette papir. I slutningen af denne linje kan vi se i parentes, at rdba'en svarer til fil#3, blok#10 (3/10).
Den tredje linje beskriver SCN for datablokken. I vores tilfælde er SCN 0x0000.00046911. Datablokkens hale er sammensat af de sidste to bytes af SCN (6911) tilføjet typen (06) og sekvensen (02). Hvis nedbrydningen af halen ikke matcher disse tre værdier, så ved systemet, at blokken er inkonsekvent og skal gendannes. Selvom denne haleværdi vises i begyndelsen af blokdumpet, gemmes den fysisk i slutningen af datablokken.
Bloktypen vises på den fjerde linje. Nogle af de gyldige typer svarer til følgende tabel:
Type Betydning
0x02 fortryd blok
0x06 tabel- eller indeksdatablok
0x0e fortryd segmentoverskrift
0x10 datasegmenthovedblok
0x17 bitmappet datasegmentoverskrift
"Objekt-id på blok?" linje fortæller os, om dette objekt er i SYS.OBJ$ eller ej. Siden Oracle 6 skal dette altid være "Y". Hvis du ser på den næste linje, fortæller seg/obj-værdien os segmentets objekt-id (i hex). I vores eksempel er dette 0x6d9c. Hex '6D9C' er '28060' i decimal. Vi kan bekræfte, at dette er vores tabel med følgende forespørgsel:
ORA9I SQL> vælg ejer, objektnavn fra dba_objects
2 hvor object_id=28060;
OWNER OBJECT_NAME
--------- ------------------------------
PEASLAND EMP
Som vi havde håbet, er dette vores bord.
csc-værdien er Cleanout System Change-nummeret. Denne værdi fortæller os, hvornår blokrensning blev udført på denne blok. Forhåbentlig matcher det datablokkens SCN. Itc-værdien er antallet af interesserede transaktionslister. I vores tilfælde er der to transaktioner interesseret i denne blok. De interesserede transaktioner vises i slutningen af vores eksempel. Vi kan se transaktions-id'et (Xid) for disse to transaktioner. Disse transaktions-id'er svarer til rollback-segmenter, der bruges til at behandle vores transaktioner.
Flaget (flg) er enten "-" eller "O", bruges til at angive, om denne blok er på en freeliste. Hvis blokken er på en freeliste, vil flaget være "0". Hvis det ikke er på en freeliste, vil flaget være "-". Vores pågældende blok er på freelisten.
Nå, det var ret meget information, og vi har ikke rigtig set for meget på lossepladsen. Lad os se på næste afsnit af datablokdumpen.
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] now=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
Tsiz-værdien viser os mængden af ledig plads i blokken til data. Her får vi '1fa0', som oversættes til 8.096 bytes brugbart rum. Resten af vores 8.192 byte blok bruges til overhead, såsom blokoverskriften.
ntab-værdien viser os, hvor mange tabeller der er gemt i denne blok. Medmindre denne blok tilhører en klynge, vil denne værdi være '1'. Den smalle værdi fortæller os, hvor mange rækker data der er gemt i denne blok. Vores datablok har 14 rækker med data.
Fra adressen '0xe' får vi en mappe til hver række. Vi kan se, at den første række (indeksindtastning nul) starter ved forskudt adresse til blokken '0x1c30'. Hver af blokkens rækker følger herfra. På denne måde kan en række virkelig hurtigt findes. Husk at en ROWID dybest set er en pegepind til en unik række. I Oracle 8+ er ROWID af formen O.F.B.R (eller objectno,relativefno,blockno,rowno). Så når systemet hurtigt peger på en bestemt blok i en bestemt fil, peger rækkenummeret på en plads i denne mappe. Biblioteket peger derefter på en bestemt placering i blokken. Dette er starten på den række.
Nu hvor vi har en køreplan til vores datablok, lad os se på resten af sporingsfilen for at se de faktiske rækker af data i blokken.
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
De faktiske rækkedata starter med sætningen "block_row_dump:". Derefter gives en række data. Jeg har kun vist en række data her, da resten ligner hinanden. Vi kan se, at denne række tilhører tabel '0' (faneblad) i vores klynge. Da der ikke er nogen klynge i vores eksempel, har vi ikke mere end én tabel, så denne værdi vil være nul. Vi kan også se, at dette er række '0', og adressen på den række er angivet. Denne adresse skal svare til vores køreplan nævnt ovenfor.
'tl'-værdien giver os det samlede antal bytes for denne række, inklusive eventuelle overhead. Vi kan se, at denne række optager 39 bytes. 'cc'-værdien giver os et kolonneantal. Vi har otte kolonner i denne række. Dette kan nemt verificeres ved at lave en DESCRIBE på tabellen og tælle kolonnerne eller ved at forespørge USER_TAB_COLUMNS.
'fb'-værdien giver os flag om rækken. 'H' betyder, at vi har hovedet af rækken. 'F' betyder, at vi har det første stykke af rækken. 'L' betyder, at vi også har det sidste stykke af rækken. Da dette er det første og sidste stykke af rækken, er rækken ikke lænket. Da dette også er toppen af rækken, er rækken ikke blevet migreret.
Resten af oplysningerne for rækken er dataene for hver kolonne. For eksempel har vi i kolonne 1 følgende ASCII-tegnkoder, "53 4d 49 54 48". Et hurtigt kig på et ASCII-konverteringsdiagram vil fortælle os, at disse tegn er "SMITH". Hvis du er bekendt med eksempel-EMP-tabellen, vil du vide, at SMITH er en af vores medarbejdere. Bemærk, at kolonne 6 er NULL. Kolonne 4 er HIREDATE-kolonnen. Dette er en DATE-datatype. Fra denne blok kan du nemt verificere, at DATE-datatypen kræver syv bytes lagring. Kolonne 0 indeholder et tal. De tre bytes her er repræsentationen af det tal.