Procurar objeto danificado pelo número de página danificado no MS SQL Server 2005

Um dia desses, um dos bancos de dados do MS SQL Server mudou para Suspeito, havia uma mensagem de erro no log:
Msg 7105, nível 22, estado 9, linha 14
O ID do banco de dados 6, página (1: 386499), o slot 0 para o nó do tipo de dados LOB não existe. Isso geralmente é causado por transações que podem ler dados não confirmados em uma página de dados. Execute DBCC CHECKTABLE.

O banco de dados foi transferido para o Emergency e tentou executar o DBCC CHECKDB, mas a execução foi imediatamente interrompida:
Msg 8921, Nível 16, Estado 1, Linha 13
Cheque encerrado. Uma falha foi detectada ao coletar fatos. Possivelmente tempdb sem espaço ou uma tabela do sistema é inconsistente. Verifique os erros anteriores.
Msg 7105, nível 22, estado 9, linha 13
O ID do banco de dados 6, página (1: 386499), o slot 0 para o nó do tipo de dados LOB não existe. Isso geralmente é causado por transações que podem ler dados não confirmados em uma página de dados. Execute DBCC CHECKTABLE.

O comando DBCC CHECKALLOC foi interrompido com um erro semelhante. Tudo foi complicado pelo fato de o SQL Server ser a versão 9.0.1399, ou seja, RTM, sem atualizações.

As tentativas de usar a dica TABLOCK e aumentar explicitamente o nível de isolamento da transação não levaram a nada (houve espaço em disco suficiente com tempdb e DBCC CHECKALLOC com WITH ESTIMATEONLY falhou com o mesmo erro). Eu realmente não queria colocar o SP em um servidor com um banco de dados danificado e era completamente incompreensível com qual objeto específico o problema era. Além disso, parecia que a mensagem DBCC CHECKDB tinha pouco a ver com a realidade, pois havia um registro em msdb.dbo.suspect_pages, mas o número da página era diferente daquele que o DBCC CHECKDB imprimiu.

Para seguir as instruções do DBCC CHECKDB e executar o DBCC CHECKTABLE, você precisava conhecer a tabela. E após uma longa pesquisa, uma instrução foi encontrada .
Nota
Peço desculpas por os números da tabela nas mensagens de erro e no código não corresponderem. Fiz erros nos logs e, depois disso, executo o código em um ambiente de teste em outra base ao vivo.

Usamos o algoritmo abaixo para determinar o object_id de ambas as páginas - do DBCC CHECKDB e O problema estava na página de unknown_pages

A primeira coisa a fazer é executar (no contexto de um banco de dados corrompido) é DBCC PAGE (id_dados de banco de dados, id_do_arquivo, id_de_página, printopt):

DBCC TRACEON (3604); DBCC PAGE(5, 1, 3242342, 0) DBCC TRACEOFF (3604); 

ou:

 DBCC PAGE(5, 1, 3242342, 0) WITH TABLERESULTS. 

Se você tiver sorte (ou estiver jogando em uma base ativa), como resultado, verá o campo Metadados: ObjectId e, de fato, o id_do_objeto desejado:



No entanto, se você, como nós, tiver azar, verá o seguinte:
Metadados: = Indisponível no banco de dados offline
Se os metadados não estiverem disponíveis, nem tudo estiver perdido, neste caso, precisamos do campo m_objId (AllocUnitId.idObj). Se m_objId = 255, o problema é fechar o artigo e procurar outra coisa (tente fazer o script de tudo que puder e remover os dados, execute o DBCC CHECKDB com os parâmetros de "recuperação" às cegas, etc.).
A captura de tela mostra que eu tenho m_objId = 9931, ou seja, pode continuar.

Agora você precisa fazer alguns cálculos para calcular o ID da unidade de alocação (mais sobre as unidades de alocação podem ser encontradas aqui ):
ID da unidade de alocação = m_objid * 65536 + (2 ^ 56)
No nosso caso:
ID da unidade de alocação = 9931 * 65536 + (2 ^ 56) = 72057594688765952

Portanto, conhecendo o ID da unidade de alocação, você pode ver o que temos na exibição do sistema sys.allocation_units :

 SELECT * FROM sys.allocation_units WHERE allocation_unit_id = 72057594688765952 



E lá, no tipo de caso = 1 ou 3 (IN_ROW_DATA, ROW_OVERFLOW_DATA), a coluna container_id = sys.partitions.hobt_id ("Heap-Or-B-Tree ID"), ou seja, Você pode executar a solicitação:

 SELECT * FROM sys.partitions WHERE hobt_id = 72057594661437440 



E aqui já existe o object_id e index_id corretos. Agora você pode ver o que temos em sys.objects e sys.indexes e apenas execute:

 SELECT OBJECT_NAME(object_id) 

Felizmente, tanto na situação real quanto aqui, o índice de não cluster se confirmou, após a reestruturação na qual tudo voltou ao normal (na verdade, não, mas isso é outra história).

Referências :
Como usar a página DBCC
Solução de problemas e correção da corrupção no nível da página do SQL Server
O que são unidades de alocação?
Localizando um nome de tabela a partir de um ID de página
sys.allocation_units

Source: https://habr.com/ru/post/pt430824/


All Articles