A algumas semanas o pessoal me ligou com um problema em uma base de um cliente.
A base possuia 180GB, divididos em 6 arquivos todos no FG Primary,,, Dois destes arquivos estavam em unidades que apresentaram problemas e o pessoal conseguiu recuperar utilizando aqueles programas de recuperação RAW.
Quando acessei o ambiente a base estava em modo Emergencial e não aceitava nenhuma interação, o errorlog mostrava que quando ele tentava ler a base apresentava erro 5172 que o cabeçalho do “arquivo X” não era um cabeçalho válido para um arquivo de banco de dados e que a propriedade de FGID era incorreta…
hhhhmmmm… isso não estava cheirando muito bem…
O melhor dos mundos seria recuperar a base utilizando um backup mais recente, movendo os arquivos para unidades de disco que estivessem integras, aplicar alguns LOG´s, todos felizes . boa noite e bons sonhos…
Mas não… ai não tem graça…
Backup? nada… nunca foi feito porque a base era grande e “deixava tudo lento”
HA? Cluster ou Mirror até mesmo log Shipping ??? um sonoro não…
OK… basicamente é um caso perdido… mas vamos ver o que da pra tentar fazer…
Usando um editor Hexadecimal abri o arquivos 03 e fui tentar entender o que ele estava reclamando com o header do arquivo… aí me deparo com isso:
Uma beleza… basicamente o arquivo todo esta com problema… mas se eu conseguisse colocar a base pelo menos online talvez o CHECKDB conseguiria excluir a massa de dados com problema e partiriamos dali…
Abri o outro arquivo que o SQL havia conseguido carregar para comprar o conteúdo e era totalmente diferente… Feitas algumas modificações… consegui fazer o SQL mostrar outra mensagem de erro… “The PageAudit property is incorrect”
Ta bom… relendo o arquivo o valor para 0x00 – Header Version – deve ser 0x01, o valor para 0x01 – m_type – deve ser entre 0x01 e 0x66, o valor de 0x04 – m_flagbits – não pode ser 0x02, o valor de 0x18 – m_objid – deve ser 0x63 ou superior e assim vai por uma parte…
Mas mesmo com as modificações, não consegui trazer a base online…
Em uma situação onde não existe nenhum backup, nenhum tipo de plano de contingência, não existe outra opção que traga a base de volta, o que sobra é: deixe o cracha na mesa, atualize seu curriculo (exclua esta empresa do CV) e perca a CTPS, dependendo do caso mude de cidade…
Hoje, não se justifica este tipo de descaso, o negócio depende de informação, de continuidade. Unidades de backup não são mais tão caras, podemos montar um ambiente razoavelmente barato com mirror, por exemplo, a baixo custo, existem opções. As pessoas só percebem o quanto a informação é imporante depois que perde.
Mesmo que saiba o que fazer, é importante treinar para situações complicadas…
É melhor fazer muita tentativa em erro em um ambiente controlado do que no ambiente de produção,,, certo?
Então,,, antes de mais nada… eu sei que você sabe,,, mas não custa nada relembrar,,,
NUNCA FAÇA ISSO EM PRODUÇÃO !!!
Bom,,, com isso em mente,,, vamos começar,,,
1. Vamos criar uma base:
CREATE DATABASE [corrompeu] GO
2. Vamos alterar o modo de recovery da base:
alter database corrompeu set recovery full GO
3. Agora vamos colocar uma tabela:
use corrompeu GO
create table vendas ( vendasID int identity, clienteID int default convert(int, 100000 * RAND()), vendaData datetime default getdate(), vendaTotal money ) GO
4. Adicionamos um índice pra dar gosto…
create clustered index vendaCI on vendas (vendasID) GO
5. Colocamos uns dados,,,
set nocount ON GO
declare @conta INT select @conta = 0 while (@conta < 50000) begin insert into vendas (vendaTotal) values (100*RAND()) select @conta = @conta +1 end GO
7. E vamos fazer uns backups
use master GO
backup database corrompeu to disk = ‘d:\db01\local\corrompeu_1.bak’ with init go
backup log corrompeu to disk = ‘d:\db01\local\corrompeu_2.trn’ go
8. Bom,,, com os backups feitos,,, vamos ver as páginas que foram criadas,,,
dbcc ind (‘corrompeu’,‘vendas’,1) GO
9. Escolha uma página e coloque no lugar do XXXXX
DBCC TRACEON (3604) GO dbcc page(‘corrompeu’,1,XXXXX,3)
Você deve ver alguma coisa do tipo:
A página que eu escolhi foi a 1:493. Meu vendasID vai do registro 24256 até 245000.
Agora começa a ficar legal….
10. Vamos colocar a base offline:
alter database corrompeu set offline GO
11. Agora um simples cálculo…
select 493*8192 GO
Temos o número em decimal da localização da página no arquivo .mdf
12. Com esse número vamos utilizar um editor Hexadecimal para achar a linha dentro do arquivo .mdf.
Dentro do editor de Hexadecimal, abra o arquivo .mdf (neste caso D:\DB01\Corrompeu.mdf).
Clique em “Localizar” e escolha “Ir Para”.
Escolha a opção “DEC”, digite ou cole o resultado do cálculo acima e depois cliente em “HEX”, ele vai converter o valor para Hexadecimal.
clique em “OK”
Altere a linha onde o cursor esta piscando para 00 (zero-zero), ela vai ficar em vermelho.
Salve o arquivo.
13. Agora dentro do SQL vamos voltar com a base online:
alter database corrompeu set online GO
14. Usando o DBCC CHECKDB, vamos ver se a base está realmente corrompida…
Legal,,, temos uma base corrompida…
15. vamos tentar um select na tabela,,, e olha lá o erro,,,
Bom,,, legal… temos uma base corrompida,,, e agora?
Agora fica legal… o objetivo é deixar a base operacional sem perder informação… imagine que essa é sua base de produção e justamente essa tabela é a folha de pagamento,,, olha que legal…
Uma dica: tentei fazer o processo de restore no SQL Server Denali CTP 1 e não consegui restaurar apenas a página, tive que remover ela e reinserir os dados através de outra base, fiz o mesmo processo de restore apenas da página no SQL Server 2008 R2 e funcionou sem problema.
Se alguém precisar de ajuda é só deixar o comentário…
ATUALIZAÇÃO:
Segue o link do SkyDrive com a base, backup e o script desse exemplo:
Você já passou por aquela situação de ter que fazer um backup de uma base que não é pequena e não ter ideia de quanto tempo vai demorar? Você fica olhando aquela circulo maldito do SSMS rodando e rodando e nada, quando ele mostra alguma coisa é de 10% em 10%,,, Ou quando executa um script ele também fica nos 10% em 10%,,,