Eu estava trabalhando recentemente em algumas corrupções de blocos de dados e precisei despejar alguns blocos de dados para verificar seu conteúdo. Eu tive que descartar um artigo que escrevi há muito tempo, que mostrava como fazer isso. O que se segue é uma parte desse papel:
Para despejar um bloco pertencente a uma tabela, você precisará saber o número do arquivo e o número do bloco desse bloco. Se você já sabe o número do arquivo e o bloco, está tudo pronto. Se você não souber o número do arquivo e o bloco, poderá consultar DBA_EXTENTS para obter essas informações. Agora que sabemos quais arquivos e blocos contêm nossa tabela, vamos despejar um bloco de amostra da tabela. Isto se faz do seguinte modo:
ORA9I SQL> altera o arquivo de dados de despejo do sistema 3 bloco 10;
Sistema alterado.
Você pode despejar um intervalo de blocos com o seguinte comando:
ORA9I SQL> altera arquivo de dados de despejo do sistema 3 bloco mín. 10 bloco máx. 12;
Sistema alterado.
Vamos agora ver o conteúdo de despejar um bloco.
Iniciar dump de blocos de dados 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 tipo:0x06=trans data
Bloquear cabeçalho dump:0x00c0000a
ID do objeto no bloco? 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
Este é o início do dump do bloco de dados. A primeira linha nos diz que estamos despejando o arquivo#3, começando no bloco#10 (minblk) e terminando com o bloco#10 (maxblk). Se tivéssemos despejado mais de um bloco de dados, esses valores representariam um intervalo. O endereço do bloco de dados relativo (rdba) é 0x00c0000a. Para obter mais informações sobre o rdba, consulte uma seção posterior neste documento. No final desta linha, podemos ver entre parênteses que o rdba corresponde ao arquivo#3, bloco#10 (3/10).
A terceira linha descreve o SCN do bloco de dados. No nosso caso, o SCN é 0x0000.00046911. A cauda do bloco de dados é composta pelos dois últimos bytes do SCN (6911) anexados com o tipo (06) e a sequência (02). Se a decomposição da cauda não corresponder a esses três valores, o sistema saberá que o bloco é inconsistente e precisa ser recuperado. Embora esse valor final apareça no início do dump do bloco, ele é armazenado fisicamente no final do bloco de dados.
O tipo de bloco aparece na quarta linha. Alguns dos tipos válidos correspondem à tabela a seguir:
Tipo Significado
bloco de desfazer 0x02
bloco de dados de tabela ou índice 0x06
cabeçalho de segmento de desfazer 0x0e
bloco de cabeçalho de segmento de dados 0x10
cabeçalho de segmento de dados em bitmap 0x17
O "ID do objeto no bloco?" linha nos diz se este objeto está ou não em SYS.OBJ$. Desde o Oracle 6, isso deve sempre ser “Y”. Se você olhar para a próxima linha, o valor seg/obj nos diz o id do objeto do segmento (em hexadecimal). Em nosso exemplo, isso é 0x6d9c. Hex '6D9C' é '28060' em decimal. Podemos verificar que esta é a nossa tabela com a seguinte consulta:
ORA9I SQL> selecione o proprietário,object_name de dba_objects
2 onde object_id=28060;
OWNER OBJECT_NAME
---------- -------------------------------
PEASLAND EMP
Como esperávamos, esta é a nossa mesa.
O valor csc é o número de alteração do sistema de limpeza. Este valor nos informa quando a limpeza do bloco foi realizada neste bloco. Espero que corresponda ao SCN do bloco de dados. O valor itc é a Contagem da Lista de Transações Interessadas. No nosso caso, existem duas transações interessadas neste bloco. Essas transações interessadas aparecem no final do nosso exemplo. Podemos ver o ID da transação (Xid) dessas duas transações. Esses IDs de transação correspondem a segmentos de rollback que são usados para processar nossas transações.
O sinalizador (flg) é “-” ou “O”, usado para indicar se este bloco está em uma lista livre. Se o bloco estiver em uma lista livre, o sinalizador será “0”. Se não estiver em uma lista livre, o sinalizador será “-”. Nosso bloco em questão está na freelist.
Bem, isso foi bastante informação e nós realmente não olhamos muito para o lixo. Vejamos a próxima seção do dump do bloco de dados.
data_block_dump
===============
tsiz:0x1fa0
hsiz:0x2e
pbl:0x024d015c
bdba:0x00c0000a
flag=-------------
ntab=1
nrow=14
fre=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
O valor tsiz nos mostra a quantidade de espaço disponível no bloco para dados. Aqui, obtemos '1fa0' que se traduz em 8.096 bytes de espaço utilizável. O restante do nosso bloco de 8.192 bytes é usado para sobrecarga, como o cabeçalho do bloco.
O valor ntab nos mostra quantas tabelas estão armazenadas neste bloco. A menos que este bloco pertença a um cluster, este valor será '1'. O valor nrow nos diz quantas linhas de dados são armazenadas neste bloco. Nosso bloco de dados tem 14 linhas de dados.
Começando no endereço ‘0xe’, obtemos um diretório para cada linha. Podemos ver que a primeira linha (entrada de índice zero) começa no endereço de deslocamento para o bloco '0x1c30'. Cada uma das linhas de blocos segue daqui. Desta forma, uma linha pode ser encontrada muito rapidamente. Lembre-se que um ROWID é basicamente um ponteiro para uma linha única. No Oracle 8+, o ROWID está no formato O.F.B.R (ou objectno,relativefno,blockno,rowno). Portanto, quando o sistema aponta rapidamente para um bloco específico em um arquivo específico, o número da linha aponta para um slot nesse diretório. O diretório então aponta para um local específico no bloco. Este é o início dessa linha.
Agora que temos um roteiro para nosso bloco de dados, vamos examinar o restante do arquivo de rastreamento para ver as linhas reais de dados no bloco.
block_row_dump:
tab 0, linha 0, @0x1c30
tl:39 fb:--H-FL-- lb:0x0 cc:8
col 0:[ 3] c2 4a 46
coluna 1:[ 5] 53 4d 49 54 48
coluna 2:[ 5] 43 4c 45 52 4b
coluna 3:[ 3] c2 50 03
coluna 4:[ 7] 77 b4 0c 11 01 01 01
coluna 5:[ 3] c2 09 19
coluna 6:*NULL*
coluna 7:[ 2] c1 15
Os dados reais da linha começam com a frase “block_row_dump:”. Em seguida, uma linha de dados é fornecida. Eu mostrei apenas uma linha de dados aqui, pois o resto é semelhante. Podemos ver que esta linha pertence à tabela '0' (aba) do nosso cluster. Como não há cluster em nosso exemplo, não temos mais de uma tabela, então esse valor será zero. Também podemos ver que esta é a linha '0' e o endereço dessa linha é fornecido. Este endereço deve corresponder ao nosso roteiro mencionado acima.
O valor 'tl' nos dá o número total de bytes para esta linha, incluindo qualquer sobrecarga. Podemos ver que esta linha ocupa 39 bytes. O valor 'cc' nos dá uma contagem de colunas. Temos oito colunas nesta linha. Isso pode ser facilmente verificado fazendo um DESCRIBE na tabela e contando as colunas, ou consultando USER_TAB_COLUMNS.
O valor 'fb' nos dá sinalizadores sobre a linha. 'H' significa que temos a cabeça da fila. 'F' significa que temos o primeiro pedaço da linha. 'L' significa que também temos o último pedaço da linha. Como esta é a primeira e a última parte da linha, a linha não é encadeada. Como este também é o cabeçalho da linha, a linha não foi migrada.
O restante das informações da linha são os dados de cada coluna. Por exemplo, na coluna 1, temos os seguintes códigos de caracteres ASCII, “53 4d 49 54 48”. Uma rápida olhada em um gráfico de conversão ASCII nos dirá que esses caracteres são “SMITH”. Se você estiver familiarizado com a tabela EMP de amostra, saberá que SMITH é um de nossos funcionários. Observe que a coluna 6 é NULL. A coluna 4 é a coluna HIREDATE. Este é um tipo de dados DATE. A partir deste bloco, você pode verificar facilmente que o tipo de dados DATE requer sete bytes de armazenamento. A coluna 0 contém um número. Os três bytes aqui são a representação desse número.