Jag arbetade nyligen med några datablockkorruptioner och jag behövde dumpa några datablock för att verifiera dess innehåll. Jag var tvungen att borsta bort ett papper som jag skrev för länge sedan som visade hur man gör detta. Vad som följer är en del av det dokumentet:
För att dumpa ett block som tillhör en tabell måste du känna till filnumret och blocknumret för det blocket. Om du redan känner till filnumret och blockeringen är allt klart. Om du inte känner till filnumret och blockeringen kan du fråga DBA_EXTENTS för den informationen. Nu när vi vet vilken fil och vilka block som håller vårt bord, låt oss dumpa ett exempelblock av tabellen. Detta görs på följande sätt:
ORA9I SQL> ändra systemdumpdatafil 3 block 10;
Systemet har ändrats.
Du kan dumpa ett antal block med följande kommando:
ORA9I SQL> ändra systemdumpdatafil 3 block min 10 block max 12;
Systemet har ändrats.
Låt oss nu titta på innehållet i att dumpa ett block.
Startdumpningsdatablock tsn:3 fil#:3 minblk 10 maxblk 10
buffert tsn:3 rdba:0x00c0000a (3/10)
scn:0x0000.00046911 seq:04g :0x69110602
frmt:0x02 chkval:0x579d typ:0x06=trans data
Block header dump:0x00c0000a
Objekt-id på 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.000469000 /30004690000000000.000469000 00000101 uba:0x00800033.0099.04 C--- 0 scn 0x0000.00046906
Detta är början på datablockdumpen. Den första raden talar om för oss att vi dumpar fil#3, börjar vid block#10 (minblk) och avslutar med block#10 (maxblk). Hade vi dumpat mer än ett datablock skulle dessa värden representera ett intervall. Den relativa datablockadressen (rdba) är 0x00c0000a. För mer information om rdba, se ett senare avsnitt i detta dokument. I slutet av denna rad kan vi se inom parentes att rdba motsvarar fil#3, block#10 (3/10).
Den tredje raden beskriver SCN för datablocket. I vårt fall är SCN 0x0000.00046911. Datablockets svans är sammansatt av de två sista byten av SCN (6911) med tillslag av typen (06) och sekvensen (02). Om nedbrytningen av svansen inte matchar dessa tre värden, vet systemet att blocket är inkonsekvent och måste återställas. Även om detta slutvärde visas i början av blockdumpen, lagras det fysiskt i slutet av datablocket.
Blocktypen visas på den fjärde raden. Några av de giltiga typerna motsvarar följande tabell:
Typ Betydelse
0x02 ångra block
0x06 tabell- eller indexdatablock
0x0e ångra segmenthuvud
0x10 datasegmenthuvudblock
0x17 bitmappad datasegmentrubrik
"Objekt-ID på block?" raden talar om för oss om detta objekt finns i SYS.OBJ$ eller inte. Sedan Oracle 6 bör detta alltid vara "Y". Om du tittar på nästa rad berättar seg/obj-värdet segmentets objekt-id (i hex). I vårt exempel är detta 0x6d9c. Hex '6D9C' är '28060' i decimal. Vi kan verifiera att detta är vår tabell med följande fråga:
ORA9I SQL> välj ägare, objektnamn från dba_objects
2 där object_id=28060;
ÄGARE OBJECT_NAME
--------- ------------------------------
PEASLAND EMP
Som vi hade hoppats är det här vårt bord.
Csc-värdet är Cleanout System Change-numret. Detta värde talar om för oss när blockrensning utfördes på detta block. Förhoppningsvis matchar det datablockets SCN. Itc-värdet är räkningen av intressetransaktionslistan. I vårt fall finns det två transaktioner som är intresserade av detta block. De intresserade transaktionerna visas i slutet av vårt exempel. Vi kan se transaktions-id (Xid) för dessa två transaktioner. Dessa transaktions-ID motsvarar återställningssegment som används för att behandla våra transaktioner.
Flaggan (flg) är antingen "-" eller "O", används för att indikera om detta block finns på en frilista. Om blocket finns på en frilista kommer flaggan att vara "0". Om den inte finns på en frilista kommer flaggan att vara "-". Vårt block i fråga finns på frilistan.
Tja, det var ganska mycket information och vi har inte riktigt tittat på för mycket av soptippen. Låt oss titta på nästa avsnitt av datablocksdumpen.
data_block_dump
===============
tsiz:0x1fa0
hsiz:0x2e
pbl:0x024d015c
bdba:0x00c0000a
flagga=-------------
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ärdet visar oss mängden tillgängligt utrymme i blocket för data. Här får vi '1fa0' som översätts till 8 096 byte av användbart rum. Resten av vårt block på 8 192 byte används för overhead som blockhuvudet.
Värdet ntab visar hur många tabeller som är lagrade i detta block. Om inte detta block tillhör ett kluster kommer detta värde att vara '1'. Det smala värdet talar om för oss hur många rader med data som är lagrade i detta block. Vårt datablock har 14 rader med data.
Med början på adressen '0xe' får vi en katalog till varje rad. Vi kan se att den första raden (indexinmatning noll) börjar vid offsetadress till blocket '0x1c30'. Var och en av blockraderna följer härifrån. På så sätt kan en rad hittas riktigt snabbt. Kom ihåg att en ROWID i grunden är en pekare till en unik rad. I Oracle 8+ är ROWID av formen O.F.B.R (eller objectno,relativefno,blockno,rowno). Så när systemet snabbt pekar på ett visst block i en viss fil, pekar radnumret på en plats i den här katalogen. Katalogen pekar sedan på en specifik plats i blocket. Det här är början på den raden.
Nu när vi har en färdplan till vårt datablock, låt oss titta på resten av spårningsfilen för att se de faktiska raderna med data i blocket.
block_row_dump:
tab 0, rad 0, @0x1c30
tl:39 fb:--H-FL-- lb:0x0 cc:8
kol 0:[ 3] c2 4a 46
kol 1:[ 5] 53 4d 49 54 48
kol 2:[ 5] 43 4c 45 52 4b
kol 3:[ 3] c2 50 03
kol 4:[ 7] 77 b4 0c 11 01 01 01
kol 5:[ 3] c2 09 19
kol 6:*NULL*
kol 7:[ 2] c1 15
Den faktiska raddatan börjar med frasen "block_row_dump:". Sedan ges en rad med data. Jag har bara visat en rad med data här, eftersom resten är liknande. Vi kan se att den här raden tillhör tabellen '0' (flik) i vårt kluster. Eftersom det inte finns något kluster i vårt exempel har vi inte mer än en tabell så detta värde blir noll. Vi kan också se att detta är rad '0' och adressen till den raden anges. Denna adress bör överensstämma med vår färdplan som anges ovan.
"tl"-värdet ger oss det totala antalet byte för den här raden, inklusive eventuell overhead. Vi kan se att denna rad upptar 39 byte. "cc"-värdet ger oss ett kolumnantal. Vi har åtta kolumner i den här raden. Detta kan enkelt verifieras genom att göra en DESCRIBE i tabellen och räkna kolumnerna, eller genom att fråga USER_TAB_COLUMNS.
"fb"-värdet ger oss flaggor om raden. "H" betyder att vi har radens huvud. "F" betyder att vi har den första delen av raden. "L" betyder att vi också har den sista delen av raden. Eftersom detta är den första och sista delen av raden är raden inte kedjad. Eftersom detta också är huvudet på raden har raden inte migrerats.
Resten av informationen för raden är data för varje kolumn. Till exempel, i kolumn 1, har vi följande ASCII-teckenkoder, "53 4d 49 54 48". En snabb titt på ett ASCII-konverteringsdiagram kommer att berätta för oss att dessa tecken är "SMITH". Om du är bekant med EMP-exemplet så vet du att SMITH är en av våra anställda. Observera att kolumn 6 är NULL. Kolumn 4 är kolumnen HIREDATE. Detta är en DATE-datatyp. Från detta block kan du enkelt verifiera att datatypen DATE kräver sju byte lagring. Kolumn 0 innehåller ett nummer. De tre byten här är representationen av det numret.