Casos do Dia a Dia: Erro ao executar o comando DBCC CHECKDB
Fala Pessoal,
Ontem, ao chegar em meu ambiente de trabalho, verifiquei que minha rotina de CHECKDB de um dos meus servidores havia falhado.
JOB RUN: ‘DBA – CHECKDB’ was run on 15/3/2011 at 21:20:00
DURATION: 1 hours, 29 minutes, 17 seconds
STATUS: Failed
Até aí estava tudo bem pois ela já havia falhado anteriormente por falta de recursos disponíveis para executá-la. Entretanto, ao verificar minha planilha com o checklist diário do DBA, na aba CHECKDB, encontrei a seguinte mensagem:
DBCC CHECKDB (Nome_Database) WITH no_infomsgs executed by Nome_Usuario found 2 errors and repaired 0 errors. Elapsed time: 0 hours 20 minutes 20 seconds.
Agora a casa tinha caído.
Ao abrir o log do SQL Server, verifiquei a seguinte mensagem nas execuções do comando DBCC CHECKDB dessa database:
- Found 2 errors and repaired 0 errors.
- *DBCC database corruption
Duvido que essa frase no log do SQL Server não te da um frio na barriga também: *DBCC database corruption
Olhando o histórico do Job encontrei o seguinte resultado:
Page (1:88888888), slot 4 in object ID 77777777, index ID 1, partition ID 99999999999999999999,
alloc unit ID 6666666666666666 (type “In-row data”). Column “Nome_Coluna1” value is out of range for data type “decimal”.
Update column to a legal value. [SQLSTATE 42000] (Error 2570)
Page (1:88888888), slot 4 in object ID 77777777, index ID 1, partition ID 99999999999999999999,
alloc unit ID 6666666666666666 (type “In-row data”). Column “Nome_Coluna2” value is out of range for data type “numeric”.
Update column to a legal value. [SQLSTATE 42000] (Error 2570)
CHECKDB found 0 allocation errors and 2 consistency errors in table ‘Nome_Tabela‘ (object ID 99999999). [SQLSTATE 01000] (Error 8990)
CHECKDB found 0 allocation errors and 2 consistency errors in database ‘Nome_Database‘. [SQLSTATE 01000] (Error 8989). The step failed.
Recorri ao google e rapidamente encontrei esse KB da microsoft que utilizei como referência para resolver o problema.
Olhando em outros sites, verifiquei que esse erro era bem comum de ser encontrado em migrações do SQL Server 2000 para o SQL Server 2005 ou superior, entretanto, esse não era o meu caso pois essa base já estava criada no SQL Server 2005 a anos e o dbcc checkdb é executado diariamente nela.
Como a database que deu problema é restaurada diariamente em um servidor de teste. Verifiquei que o mesmo erro estava acontecendo na database de teste e fui encontrar uma solução.
Pelas mensagens de erro, o problema estava na mesma página de dados de um mesmo objeto (os números do post são fictícios):
Erro na Coluna 1: Page (1:88888888), slot 4 in object ID 77777777
Erro na Coluna 2: Page (1:88888888), slot 4 in object ID 77777777
Seguindo o KB e executando o comando abaixo para verificar os registros da página com problema:
DBCC TRACEON ( 3604 )
DBCC PAGE ( Nome_Database , 1 , 88888888 , 3 )
Tive o retorno de um grande result set.
Pesquisei no resultado pelo nome das duas colunas retornadas no erro e encontrei um número absurdo para uma destas colunas exatamente no slot 4, que foi retornado nos 2 erros.
Slot 4 Column 33 Offset 0x10c Length 9
Nome_COluna1 = -1634.41
Slot 4 Column 57 Offset 0x1a7 Length 9
Nome_Coluna2 = 89998897014397766.68
Sendo que a coluna 2 era do tipo numeric(15,2).
Encontrado o valor com problema, fui tentar fazer um select para encontrar toda a linha:
Essa query retornava um erro:
SELECT *
FROM Tabela
WHERE Nome_Coluna2 = 89998897014397766.68
Todavia, essa era executada com sucesso:
SELECT count(*)
FROM Tabela
WHERE Nome_Coluna2 = 89998897014397766.68
Como o count(*) retornou 1 registro, rodei um update para descobrir todo o conteúdo da linha que estava com problema:
update Tabela
set Nome_Coluna2 = 9999999999
WHERE Nome_Coluna2 = 89998897014397766.68
Com a query abaixo, verifiquei que os dois valores do slot 4 (-1634.41 e 89998897014397766.68) pertenciam a mesma linha.
SELECT *
FROM Tabela
WHERE Nome_Coluna2 = 9999999999
Como já tinha acertado o valor absurdo da coluna 2, executei o comando abaixo para testar novamente a consistência da tabela:
DBCC CHECKTABLE(‘Nome_Tabela’)
O comando continuou retornando um erro, entretanto, agora apenas para a coluna 1:
Msg 2570, Level 16, State 3, Line 1
Page (1:88888888), slot 4 in object ID 77777777, index ID 1, partition ID 99999999999999999999,alloc unit ID 6666666666666666 (type “In-row data”). Column “Nome_Coluna1” value is out of range for data type “decimal”.Update column to a legal value.
Fiz um update do valor da coluna1 para o mesmo valor:
update Tabela
set Nome_Coluna1 = -1634.41
WHERE Chave_Tabela = xxxxxx
Executei o comando abaixo para testar novamente e o mesmo não retornou nenhum erro.
DBCC CHECKTABLE(‘Nome_Tabela’)
Pronto, havia conseguido resolver o problema de consistência com a perda de apenas uma coluna de uma linha.
No meu caso real, o registro com problema foi importado de outra fonte durante a noite, então foi possível excluí-lo e importá-lo novamente.
Caso eu não tivesse essa sorte, como eu descobri o problema em um dia, era só voltar o último backup limpo dessa database e conferir o valor das colunas com problema.
Caso você não tivesse um backup limpo, com a solução que realizamos nesse post perderíamos o valor da Coluna2.
Não sei com certeza o motivo da geração do problema, pois o registro com problema foi inserido dessa forma:
INSERT INTO Tabela
SELECT Colunas FROM Tabela
WHERE …
Se fosse retornado um valor absurdo no select, seria gerado um erro no insert, então acredito que o motivo da corrupção dessa página de dados foi uma parada que aconteceu no serviço do SQL Server no dia anterior por causa de uma pressão de memória no servidor.
Conforme já havia escrito em um artigo para a revista Codificando.NET Quanto tempo levaria para descobrir uma database corrompida?, é extremamente importante possuir uma rotina de CHECKDB. Nesse caso os registros corrompidos foram poucos, mas poderiam ser muito mais. Se eu não tivesse essa rotina, o problema só seria descoberto quando algum usuário utilizá-se o valor dessa coluna, o que poderia demorar dias. Com isso, todos os meus backups estariam corrompidos.
Você ainda pode achar que esse problema é raro e se não aconteceu até hoje, nunca vai acontecer com suas databases. Eu criei minha rotina de CHECKDB a mais de um ano e nunca havia retornado nenhum erro na mesma, entretanto, agora retornou.
Fica a dica. Caso já tenha passado por esse problema e queria acrescentar alguma informação, deixe um comentário.
Gostou dessa dica?
Cadastre seu e-mail para receber novos Posts e curta minha Página no Facebook para receber Dicas de Leituras e Eventos sobre SQL Server.
Confira mais experiências do Dia a Dia de um DBA no meu Treinamento de Tarefas do Dia a Dia de um DBA.
Abraços,
Fabrício Lima
MCITP – Database Administrator
Consultor e Instrutor SQL Server
Trabalha com SQL Server desde 2006
Olá! Muito bom o artigo.
Fiquei curioso: você chegou a olhar se a base estava com PAGE CHECKSUM habilitado?
Abraços, Fabricio
Valeu!!!
Catae, estava sim.
A muito tempo atrás, todas as minhas databases que não estavam com essa opção habilitada eu habilitei(as que vieram do sql 2000). Como ela já foi criada no sql server 2005, então essa opção é default (a não ser que eu altere na model, o que não é meu caso).
Abraço
Fabrício, eu já passei por isso depois de uma migração de SQL Server 2000 para 2008, mas ao fazer o DBCC CHECKTABLE resolvi o problema….
Abraço,
Valeu por compartilhar Rodrigo.