Uno de nuestros servidores SQL informó el siguiente error recientemente:
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 después me conecté al servidor y ejecuté:
SELECT name
FROM sys.databases
WHERE database_id = 2;
Que devolvió 'tempdb'. Entonces corrí:
DBCC CHECKDB ('tempdb') WITH NO_INFOMSGS, TABLERESULTS;
Lo cual no arrojó resultados, lo que indica que no hay problemas con la base de datos afectada.
¿Cómo podría la corrupción en la base de datos dar como resultado el mensaje de error anterior sin DBCC CHECKDB
informar el problema? Supongo que si falla el cálculo de una suma de comprobación de la página, lo que hace que la página se marque como sospechosa de que no se podrá descartar ningún objeto que haga referencia a esa página, pero debo estar equivocado.
Una vez que una página se marca como 'sospechosa', ¿cómo se puede marcar como no sospechosa, o reparada, o reutilizada, o lo que sea que DBCC CHECKDB
no informe ningún problema con la página en cuestión?
Editar: 2013-02-27 13:24
Solo por diversión, intenté recrear la corrupción en TempDB asumiendo que una tabla #temp era la culpable.
Sin embargo, como no puedo configurar la SINGLE_USER
opción en TempDB, no puedo usar DBCC WRITEPAGE
para dañar una página y, por lo tanto, no puedo forzar la corrupción en TempDB.
En lugar de usar DBCC WRITEPAGE
uno, podría establecer la base de datos fuera de línea y usar un editor hexadecimal para modificar bytes aleatorios en el archivo db. Por supuesto, eso tampoco funciona en TempDB ya que el motor de base de datos no puede ejecutarse con TempDB sin conexión.
Si detiene la instancia, TempDB se recrea automáticamente en el próximo inicio; por lo tanto, eso tampoco funcionará.
Si alguien puede pensar en una manera de recrear esta corrupción, estaría dispuesto a investigar más.
Para probar la hipótesis de que una página dañada no puede repararse DROP TABLE
, creé una base de datos de prueba y utilicé el siguiente script para dañar una página, luego intenté descartar la tabla afectada. El resultado aquí fue que la tabla no se pudo eliminar; Tuve que hacerlo RESTORE DATABASE Testdb PAGE = ''...
para recuperar la página afectada. Supongo que si hubiera hecho un cambio en alguna otra parte de la página en cuestión, tal vez la página podría haber sido corregida DROP TABLE
o tal vez 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.
En este punto, te desconectas del motor de la base de datos, así que vuelve a conectarte para continuar.
USE Test;
DBCC CHECKDB WITH NO_INFOMSGS, TABLERESULTS;
La corrupción se informa aquí.
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.
La corrupción se informa aquí, DROP TABLE
falla.
/* 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';
Editar # 2, para agregar la información @@ VERSION solicitada.
SELECT @@VERSION;
Devoluciones:
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: )
Sé que esta es la Edición de Evaluación, tenemos claves para la Edición Enterprise, y pronto haremos una Actualización de Edición.
-T 3609
preservará tempdb al inicio (indocumentado pero ya conocido )