Um de nossos servidores SQL relatou o seguinte erro recentemente:
DATE/TIME: 2/25/2013 9:15:14 PM
DESCRIPTION: No catalog entry found for partition ID 9079262474267394048
in database 2. The metadata is inconsistent. Run DBCC CHECKDB to check for
a metadata corruption.
Menos de 15 minutos depois, conectei-me ao servidor e executei:
SELECT name
FROM sys.databases
WHERE database_id = 2;
O que retornou 'tempdb'. Eu então corri:
DBCC CHECKDB ('tempdb') WITH NO_INFOMSGS, TABLERESULTS;
O que não retornou resultados, indicando que não há problemas com o banco de dados afetado.
Como a corrupção no banco de dados resultou na mensagem de erro acima e ainda DBCC CHECKDB
não relatou o problema? Presumo que um cálculo de soma de verificação de página falhe, resultando na página sendo marcada como suspeita de que qualquer objeto que faça referência a essa página não possa ser descartado, mas devo estar errado.
Depois que uma página é marcada como 'suspeita', como pode ser marcada como não suspeita, ou corrigida ou reutilizada, ou qualquer outra coisa que DBCC CHECKDB
não relate nenhum problema com a página em questão?
Edit: 2013-02-27 13:24
Apenas por diversão, tentei recriar a corrupção no TempDB, assumindo que uma tabela #temp era a culpada.
No entanto, como não consigo definir a SINGLE_USER
opção no TempDB, não posso usar DBCC WRITEPAGE
para corromper uma página e, portanto, não posso forçar a corrupção no TempDB.
Em vez de usar, DBCC WRITEPAGE
pode-se definir o banco de dados offline e usar um editor hexadecimal para modificar bytes aleatórios no arquivo db. Obviamente, isso também não funciona no TempDB, pois o mecanismo do banco de dados não pode ser executado com o TempDB offline.
Se você parar a instância, o TempDB será recriado automaticamente na próxima inicialização; portanto, isso também não funcionará.
Se alguém puder pensar em uma maneira de recriar essa corrupção, eu estaria disposto a fazer pesquisas adicionais.
Para testar a hipótese de que uma página corrompida não pode ser corrigida, DROP TABLE
criei um banco de dados de teste e usei o script a seguir para corromper uma página e, em seguida, tente descartar a tabela afetada. O resultado aqui foi que a tabela não pôde ser excluída; Eu precisei para RESTORE DATABASE Testdb PAGE = ''...
recuperar a página afetada. Presumo que, se eu tivesse feito uma alteração em alguma outra parte da página em questão, talvez a página pudesse ter sido corrigida DROP TABLE
ou talvez TRUNCATE table
.
/* ********************************************* */
/* ********************************************* */
/* DO NOT USE THIS CODE ON A PRODUCTION SYSTEM!! */
/* ********************************************* */
/* ********************************************* */
USE Master;
GO
ALTER DATABASE test SET RECOVERY FULL;
BACKUP DATABASE Test
TO DISK = 'Test_db.bak'
WITH FORMAT
, INIT
, NAME = 'Test Database backup'
, SKIP
, NOREWIND
, NOUNLOAD
, COMPRESSION
, STATS = 1;
BACKUP LOG Test
TO DISK = 'Test_log.bak'
WITH FORMAT
, INIT
, NAME = 'Test Log backup'
, SKIP
, NOREWIND
, NOUNLOAD
, COMPRESSION
, STATS = 1;
GO
ALTER DATABASE test SET SINGLE_USER;
GO
USE Test;
GO
IF EXISTS (SELECT name FROM sys.key_constraints WHERE name = 'PK_temp')
ALTER TABLE temp DROP CONSTRAINT PK_temp;
IF EXISTS (SELECT name FROM sys.default_constraints
WHERE name = 'DF_temp_testdata')
ALTER TABLE temp DROP CONSTRAINT DF_temp_testdata;
IF EXISTS (SELECT name FROM sys.tables WHERE name = 'temp')
DROP TABLE temp;
GO
CREATE TABLE temp
(
tempID INT NOT NULL CONSTRAINT PK_temp PRIMARY KEY CLUSTERED IDENTITY(1,1)
, testdata uniqueidentifier CONSTRAINT DF_temp_testdata DEFAULT (NEWID())
);
GO
/* insert 10 rows into #temp */
INSERT INTO temp default values;
GO 10
/* get some necessary parameters */
DECLARE @partitionID bigint;
DECLARE @dbid smallint;
DECLARE @tblid int;
DECLARE @indexid int;
DECLARE @pageid bigint;
DECLARE @offset INT;
DECLARE @fileid INT;
SELECT @dbid = db_id('Test')
, @tblid = t.object_id
, @partitionID = p.partition_id
, @indexid = i.index_id
FROM sys.tables t
INNER JOIN sys.partitions p ON t.object_id = p.object_id
INNER JOIN sys.indexes i on t.object_id = i.object_id
WHERE t.name = 'temp';
SELECT TOP(1) @fileid = file_id
FROM sys.database_files;
SELECT TOP(1) @pageid = allocated_page_page_id
FROM sys.dm_db_database_page_allocations(@dbid, @tblid, null, @partitionID, 'LIMITED')
WHERE allocation_unit_type = 1;
/* get a random offset into the 8KB page */
SET @offset = FLOOR(rand() * 8192);
SELECT @offset;
/* 0x75 below is the letter 't' */
DBCC WRITEPAGE (@dbid, @fileid, @pageid, @offset, 1, 0x74, 1);
SELECT * FROM temp;
Msg 824, Level 24, State 2, Line 36
SQL Server detected a logical consistency-based I/O error: incorrect checksum
(expected: 0x298b2ce9; actual: 0x2ecb2ce9). It occurred during a read of page
(1:1054) in database ID 7 at offset 0x0000000083c000 in file 'C:\SQLServer
\MSSQL11.MSSQLSERVER\MSSQL\DATA\Test.mdf'. Additional messages in the SQL
Server error log or system event log may provide more detail. This is a
severe error condition that threatens database integrity and must be
corrected immediately. Complete a full database consistency check
(DBCC CHECKDB). This error can be caused by many factors; for more
information, see SQL Server Books Online.
Nesse ponto, você é desconectado do mecanismo de banco de dados, reconecte-se para continuar.
USE Test;
DBCC CHECKDB WITH NO_INFOMSGS, TABLERESULTS;
A corrupção é relatada aqui.
DROP TABLE temp;
Msg 824, Level 24, State 2, Line 36
SQL Server detected a logical consistency-based I/O error: incorrect checksum
(expected: 0x298b2ce9; actual: 0x2ecb2ce9). It occurred during a read of page
(1:1054) in database ID 7 at offset 0x0000000083c000 in file 'C:\SQLServer
\MSSQL11.MSSQLSERVER\MSSQL\DATA\Test.mdf'. Additional messages in the SQL
Server error log or system event log may provide more detail. This is a
severe error condition that threatens database integrity and must be
corrected immediately. Complete a full database consistency check
(DBCC CHECKDB). This error can be caused by many factors; for more
information, see SQL Server Books Online.
A corrupção é relatada aqui, DROP TABLE
falha.
/* assuming ENTERPRISE or DEVELOPER edition of SQL Server,
I can use PAGE='' to restore a single page from backup */
USE Master;
RESTORE DATABASE Test PAGE = '1:1054' FROM DISK = 'Test_db.bak';
BACKUP LOG Test TO DISK = 'Test_log_1.bak';
RESTORE LOG Test FROM DISK = 'Test_log.bak';
RESTORE LOG Test FROM DISK = 'Test_log_1.bak';
Edite # 2, para adicionar as informações solicitadas pela @@ VERSION.
SELECT @@VERSION;
Devoluções:
Microsoft SQL Server 2012 (SP1) - 11.0.3000.0 (X64)
Oct 19 2012 13:38:57
Copyright (c) Microsoft Corporation
Enterprise Evaluation Edition (64-bit) on Windows NT 6.2 <X64>
(Build 9200: )
Sei que esta é a Edição de Avaliação, temos chaves para a Edição Empresarial e faremos uma Atualização da Edição em breve.
-T 3609
irá preservar tempdb no início (em situação irregular, mas já conhecida )