Uno dei nostri server SQL ha segnalato di recente il seguente errore:
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.
Meno di 15 minuti dopo mi sono connesso al server ed ho eseguito:
SELECT name
FROM sys.databases
WHERE database_id = 2;
Che ha restituito "tempdb". Ho quindi eseguito:
DBCC CHECKDB ('tempdb') WITH NO_INFOMSGS, TABLERESULTS;
Che non ha restituito risultati, indicando problemi con il database interessato.
In che modo la corruzione nel database potrebbe causare il messaggio di errore sopra riportato ma DBCC CHECKDB
non segnalare il problema? Presumo che un calcolo del checksum della pagina fallisca, facendo sì che la pagina venga contrassegnata come sospetta che qualsiasi oggetto che fa riferimento a quella pagina non possa essere eliminato, ma devo sbagliarmi.
Una volta che una pagina è contrassegnata come "sospetta", come può essere contrassegnata come non sospetta, o riparata, o riutilizzata, o qualsiasi altra cosa che DBCC CHECKDB
non segnala alcun problema con la pagina in questione?
Modifica: 27/02/2013 13:24
Solo per divertimento, ho provato a ricreare la corruzione in TempDB ipotizzando che il colpevole fosse una tabella #temp.
Tuttavia, poiché non posso impostare l' SINGLE_USER
opzione in TempDB, non posso usare DBCC WRITEPAGE
per corrompere una pagina e quindi non posso forzare la corruzione in TempDB.
Invece di DBCC WRITEPAGE
usarne uno, è possibile impostare il database offline e utilizzare un editor esadecimale per modificare byte casuali nel file db. Naturalmente, ciò non funziona neanche su TempDB poiché il motore di database non può essere eseguito con TempDB offline.
Se si interrompe l'istanza, TempDB viene ricreato automaticamente al successivo avvio; quindi anche questo non farà il trucco.
Se qualcuno potesse pensare a un modo per ricreare questa corruzione, sarei disposto a fare ulteriori ricerche.
Per verificare l'ipotesi che una pagina danneggiata non possa essere riparata da DROP TABLE
me, ho creato un database di prova e ho usato il seguente script per corrompere una pagina, quindi ho cercato di eliminare la tabella interessata. Il risultato qui era che la tabella non poteva essere cancellata; Ho dovuto per RESTORE DATABASE Testdb PAGE = ''...
recuperare la pagina interessata. Suppongo che se avessi apportato una modifica a qualche altra parte della pagina in questione, forse la pagina avrebbe potuto essere corretta DROP TABLE
o forse 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.
A questo punto ti disconnetti dal motore di database, quindi riconnettiti per continuare.
USE Test;
DBCC CHECKDB WITH NO_INFOMSGS, TABLERESULTS;
La corruzione è riportata qui.
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 corruzione è riportata qui, DROP TABLE
non riesce.
/* 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';
Modifica # 2, per aggiungere le informazioni sulla VERSIONE @@ richieste.
SELECT @@VERSION;
Ritorna:
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: )
So che questa è la versione di valutazione, abbiamo le chiavi per la versione Enterprise e presto eseguiremo un aggiornamento della versione.
-T 3609
manterrà tempdb all'inizio (non documentato ma già noto )