Correction des bases SQL Server corrompues

En pratique il est extrêmement rare de voir une base de données SQL server se corrompre. Aucun bug concernant le moteur de stockage de Microsoft SQL Server n’a été détecté depuis près de 20 ans. Cela signifie en pratique que de telles erreurs ne peuvent intervenir qu’à l’extérieur du service SQL Server (disque défectueux, contrôleur disque défaillant…). Néanmoins, il est important de réagir au plus vite après détection pour corriger le problème.
Cet article vous apprend comment réparer au mieux votre base en essayant de perdre le moins de données possible.

L’article est disponible au format PDF :

Correction des bases de donnees SQL Server corrompues

Les scripts SQL relatifs à cet article figurents si dessous :

/******************************************************************************
***   Correction des bases SQL Server corrompues - principaux scrips SQL.   ***
*******************************************************************************
* Frédéric Brouard - SQLpro - MVP SQL Server *** SQL spot SARL (PARIS / PACA) *
* le blog : http://blog.developpez.com/sqlpro                                 *
* le site : http://sqlpro.developpez.com                                      *
*******************************************************************************
* Principaux scripts Transact SQL associés à l'article                        *
******************************************************************************/


--> #01 - Pour retrouver la base de données (l’identifiant qui a été révélé est ???)
SELECT name
FROM   sys.DATABASES
WHERE database_id = ???;   --> identifiant de la base

--> #02 - Pour retrouver dans la base $$$ l'objet contenu dans une page (pour nous la page ??? du fichier !!!), lancez le lot de commande :
DBCC TRACEON (3604)
--> pour rediriger la sortie de la commande DBCC PAGE vers SSMS
GO
DBCC PAGE($$$, !!!, ???, 1)
--> syntaxe : nom_base, n° fichier, n° page, mode de visu (0, 1, 2 ou 3)
GO

--> #03 - Pour retrouver dans la base $$$ l'objet contenu dans une page ??? du fichier !!!, avec affichage en mode table
DBCC PAGE($$$, !!!, ???, 0) WITH TABLERESULTS
GO

--> #04 - Pour trouver l’index et la tableconcernée, faite la requête suivante :
SELECT s.name AS TABLE_SCHEMA, o.name AS TABLE_NAME,
       o.type_desc AS TABLE_TYPE, i.name AS INDEX_NAME,
       CASE WHEN i.index_id  identifiant de l'objet
  AND  i.index_id = 000;   --> identifiant de l'
INDEX

--> #05 - identifie les contraintes FOREIGN KEY à « débrancher », en connaissant le nom de la table ??? et son schema !!! dont l’index 000 de contrainte PRIMARY KEY ou UNIQUE est à réparer
SELECT RC.CONSTRAINT_NAME, FK.TABLE_SCHEMA, FK.TABLE_NAME,
       'ALTER TABLE [' + FK.TABLE_SCHEMA + '].[' + FK.TABLE_NAME
       + '] DROP CONSTRAINT [' + FK.CONSTRAINT_NAME + '];' AS DROP_COMMAND
FROM   INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS UK
       INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
             ON UK.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME
             AND UK.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA
       INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS FK
             ON RC.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
             AND RC.CONSTRAINT_SCHEMA = FK.CONSTRAINT_SCHEMA
       INNER JOIN sys.objects AS o
             ON o.object_id = OBJECT_ID(UK.TABLE_SCHEMA+'.'+UK.TABLE_NAME)
       INNER JOIN sys.indexes AS i
             ON o.object_id = i.object_id
             AND i.name = UK.CONSTRAINT_NAME
WHERE  UK.TABLE_SCHEMA = '!!!'       --> schéma SQL de la table concernée
AND    UK.TABLE_NAME   = '???'       --> nom de la table concernée
AND    index_id        = 000         --> identifiant de l'index concerné

--> #06 - réparer en mode REPAIR_REBUILD dans la base $$$
ALTER DATABASE [$$$]
   SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
DBCC CHECKTABLE ('!!!.???', REPAIR_REBUILD); --> schema !!!, table ???

--> #07 - réparer en mode REPAIR_ALLOW_DATA_LOSS dans la base $$$
ALTER DATABASE [$$$]
   SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
DBCC CHECKTABLE ('!!!.???', REPAIR_ALLOW_DATA_LOSS)

--> #08 - Placement de la base $$$ en mode EMERGENCEY
ALTER DATABASE [$$$] SET EMERGENCY
GO

--> #09 - réparer la base en mode REPAIR_ALLOW_DATA_LOSS dans la base $$$ après mise en EMERGENCY
ALTER DATABASE [$$$]
   SET SINGLE_USER;
GO
DBCC CHECKDB ([$$$], REPAIR_ALLOW_DATA_LOSS) WITH NO_INFOMSGS;
GO
ALTER DATABASE [$$$] SET MULTI_USER;
GO

--> #10 - Vérification après réparation
DBCC CHECKDB ([$$$]);
GO
USE [$$$]
GO
DBCC CHECKCONSTRAINTS ();


-------------------------------------------------------------------------------
--> A1 - déplacement des fichiers d’une base
-------------------------------------------------------------------------------

USE [$$$] --> nom de la base à déplacer

SELECT name, type_desc, physical_name,
       SIZE * 8 / 1024.0 AS SIZE_MB
FROM   sys.database_files;

SELECT name, type_desc, physical_name,
       SIZE * 8 / 1024.0 AS SIZE_MB
FROM   sys.master_files
WHERE  database_id = DB_ID('MA_BASE'); --> nom de la base à déplacer
GO



DECLARE @NEWPATH NVARCHAR(256);
SET @NEWPATH = 'D:\DATABASES\'; --> nouveau chemin à prendre en compte

SELECT name, type_desc, physical_name,
       size * 8 / 1024.0 AS SIZE_MB,
       N'
MOVE /Y "' + physical_name + N'" "'
       + @NEWPATH + N'"
' AS OS_COMMAND
FROM   sys.master_files
WHERE  database_id = DB_ID('
$$$'); --> nom de la base à déplacer
GO



DECLARE @OSCMD VARCHAR(8000);
SET @OSCMD = '
C:\DATABASES\'; --> nouveau chemin à prendre en compte
SET @OSCMD = '
"' + @OSCMD +'"';
SELECT @OSCMD = '
"' + physical_name +'" ' + @OSCMD
FROM   sys.master_files
WHERE  database_id = DB_ID('
$$$'); --> nom de la base à déplacer
SELECT '
COPY /Y ' + @OSCMD;
GO



DECLARE @NEWPATH NVARCHAR(256);
SET @NEWPATH = N'
D:\DATABASES\'; --> nouveau chemin à prendre en compte
DECLARE @SQLCMD NVARCHAR(max);

WITH
T0 AS (SELECT DB_NAME(database_id) AS DATABASE_NAME,
              REVERSE(LEFT(REVERSE(physical_name),
                      CHARINDEX('
\', REVERSE(physical_name)) - 1))
                 AS A_FILE,
              ROW_NUMBER() OVER(ORDER BY file_id) AS N,
              COUNT(*) OVER() AS P
       FROM   sys.master_files
       WHERE  database_id = DB_ID('
$$$')), --> nom de la base à déplacer
T1 AS (SELECT DISTINCT N'
CREATE DATABASE [' + DATABASE_NAME + N'] ON ' AS SQLCMD_HEAD
       FROM   T0),
T2 AS (SELECT CAST(N'
(FILENAME = ''' + @NEWPATH + A_FILE + N''') ' AS NVARCHAR(max))
                 AS SQLCMD, N, P
       FROM   T0
       WHERE  N = 1
       UNION ALL
       SELECT SQLCMD + N'
, (FILENAME = ''' + @NEWPATH + A_FILE + N''') ', T0.N, T0.P
       FROM   T0
              INNER JOIN T2 ON T2.N + 1= T0.N)
SELECT SQLCMD_HEAD + N'
' + SQLCMD + N' FOR ATTACH;'
FROM   T1
       CROSS JOIN T2
WHERE  N = P;
Frédéric Brouard, alias SQLpro, ARCHITECTE DE DONNÉES
Expert  S.G.B.D  relationnelles   et   langage  S.Q.L
Moste  Valuable  Professionnal  Microsoft  SQL Server
Société SQLspot  :  modélisation, conseil, formation,
optimisation,  audit,  tuning,  administration  SGBDR
Enseignant: CNAM PACA, ISEN Toulon, CESI Aix en Prov.

L’entreprise SQL Spot
Le site web sur le SQL et les SGBDR

MVP Microsoft SQL
Server

Laisser un commentaire