- Recuperando dados deletados do SQL Server sem Backup Full – Parte 1
- Recuperando dados deletados do SQL Server sem Backup Full – Parte 2
- Recuperando dados deletados do SQL Server sem Backup Full – Parte 3
- Recuperando dados deletados do SQL Server sem Backup Full – Parte 4
- Recuperando dados deletados do SQL Server sem Backup Full – Parte 5
- Recuperando dados deletados do SQL Server sem Backup Full – Parte 6
Olá! Hoje, dando continuidade a nossa série, vou responder a pergunta do último post: E se nos dados que estou recuperando tinham valores NULL?
E a resposta é muito simples: Isso está junto no meio desse binário todo! Como você estudou sobre a anatomia de um registro , com os vários links que eu coloquei nos posts anteriores (né?), então aprendeu que existe um negócio chamado NULL bitmap. Basicamente é uma sequencia de bytes que indicam quais colunas tem o valor nulo ou não. Recorra aos links que coloquei anteriormente para entender com mais detalhes sobre ele.
Sabendo isso, tudo que precisamos é identificar o NULL bitmap no meio desse binário todo, de cada registro, e checar se a coluna está nula ou não. Identificar o NULL bitmap envolve, além de conhecer a anatomia do registro, um pouco de mágica matemática:
Este trecho envolve basicamente achar alguns metadados que existem no registro (Veja o Post do Paul Randal) para encontrar o resto das informações. Primeiro, eu preciso encontrar os bytes que indicam a quantidade de colunas, por dois motivos:
- Achando a posição deles eu sei onde começa o NULL bitmap
- O tamanho do NULL bitmap, isto é, quantidade de bytes que formam ele, depende da quantidade de colunas
A cada 8 colunas, ele precisa de um byte adicional. Por exemplo, uma tabela com 8 colunas, precisa de um NULL bitmap com 1 byte (8 bits, 1 pra cada coluna). Já com 10 colunas, ele vai gastar 2 bytes (16 bits, sendo apenas 10 usados). Com 16 colunas, continuamos com os 2 bytes (agora usando todos os 16 bits) e por aí vai…
Por essas razões, eu precisei gerar a coluna chamada ColCount, que me indica a quantidade de colunas. Ela começa no byte 27 porque a última coluna de tipo fixo é a DataCadastro, que começa no byte 19 e usa 8 bytes… Os bytes dela são do 19 ao 26… A quantidade de colunas sempre gasta 2 bytes (Neste caso, bytes 27 e 28).
Na subquery acima, a coluna NullBmp contém todo o NULL bitmap! Novamente, estou usando a função SUBSTRING com a coluna Registro ([RowLog Contents 0] de fn_dump_dblog) para extrair os bytes que compõe o NULL bitmap. Neste caso, o NULL bitmap começa no byte 29. E Pronto (como tenho 7 colunas, preciso de apenas 1 byte)! Agora que tenho o NULL bitmap completo, é so checar cada bit dele para saber se a respectiva coluna é nulo ou não:
- O primeiro bit (o bit 0), indica se a primeira coluna é ou não nula (neste caso sempre vai ser zero, pois é a coluna Id, que é chave primária)
- O bit 1 controla a da segunda
- O bit 2 da coluna 3 e por aí vai.
De posse do NULL bitmap, testar o valor de um binário no SQL Server, em uma posição específica, requer apenas um pouquinho de matemática (e talvez uma pesquisa no stack overflow):
A lógica é: eu crio uma coluna para cada uma das colunas das tabelas. Basicamente o valor dessa coluna é o valor do bit respectivo no NULL bitmap: 1 indica que é NULL, 0 é o contrário. Eu resolvi colocar numa lista separada para que a expressão no SELECT principal não ficasse monstruosa. Então, lá no SELECT final, eu apenas faço uma condição mais simples: Se o valor da respectiva coluna for 1, então significa que ela é NULL, então retorno o valor NULL. Caso contrário, retorna o valor resultante daquela expressão que extrai o valor original:
Para as colunas que são NOT NULL, eu nem me dou o trabalho de fazer essa verificação, pois o bit sempre será 0, como, por exemplo, é o caso da coluna Id.
Com o NULL bitmap, além de determinar quais colunas tem o valor NULL, você consegue identificar onde iniciam as colunas de tipos variáveis. E no próximo, e último post, vamos entender como lidamos com essas colunas, que, na minha opinião, são as mais chatas de recuperar!
Até lá!
DBA Team Leader na Power Tuning