Réparation de pages incohérentes dans la base de données

8

Nous avons une base de données SQL 2000. Le serveur est tombé en panne en raison d'une défaillance de la baie Raid. Maintenant, lorsque nous exécutons DBCC CHECKDB, nous obtenons une erreur indiquant qu'il y a 27 erreurs de cohérence sur 9 pages.

Lorsque nous exécutons DBCC PAGE sur ces pages, nous obtenons ceci:

Msg 8939, Level 16, State 106, Line 1
Table error: Object ID 1397580017, index ID 2, page (1:8404521). Test (m_freeCnt == freeCnt) failed. Values are 2 and 19.
Msg 8939, Level 16, State 108, Line 1
Table error: Object ID 1397580017, index ID 2, page (1:8404521). Test (emptySlotCnt == 0) failed. Values are 1 and 0.

Étant donné que l'index indiqué n'est pas en cluster et est créé par une constarint unique qui comprend 2 colonnes, nous avons essayé de supprimer et de recréer l'index. Cela a entraîné l'erreur suivante:

CREATE UNIQUE INDEX terminated because a duplicate key was found for index ID 2. Most significant primary key is '3280'. 
The statement has been terminated. 

Cependant en cours d'exécution

Select var_id,result_on
from tests
group by var_id,result_on
having count(*)>1

renvoie 0 lignes.

Voici ce que nous prévoyons de faire:

  • Restaurer une copie de plantage pré-serveur de la base de données et exécuter DBCC CHECKDB
  • Si cela revient propre, puis restaurer à nouveau sans récupération
  • Appliquer toutes les sauvegardes TLOG inférieures
  • Arrêtez l'application de production, effectuez une sauvegarde du journal de fin et appliquez-la également
  • Supprimez la base de données prod et renommez la base de données fraîchement restaurée pour la rendre prod
  • Lancer l'application prod

Quelqu'un pourrait-il s'il vous plaît percer des trous dans cette approche? Peut-être, suggérer une approche différente? Ce dont nous avons besoin, c'est d'un temps d'arrêt minimal.

Taille de la base de données SQL 2000 94 Go Le tableau contenant des pages corrompues contient plus de 460 millions de lignes de données

Merci pour l'aide.

Raj


la source
1
J'aime ton approche. Ça a du sens pour moi. Peut-être garder la base de données endommagée à côté, comme assurance ...
user24161
Aussi, quand les choses se
calmeront
(c'est-à-dire mise à niveau 2005 ou 2008)
user24161
+1 pour avoir un plan de rétablissement valide et très approprié
Andrew

Réponses:

2

Votre solution de récupération est la manière la plus simple de procéder. En supposant que vous disposiez de sauvegardes appropriées et à condition de pouvoir sauvegarder le journal des transactions de la base de données corrompue, votre stratégie est celle du manuel à mettre en œuvre.

Mais avant de poursuivre, avez-vous envisagé la possibilité de recréer uniquement la table concernée?

Parfois, vous pouvez échapper à la création d'une copie exacte de la table affectée en faisant un

select *
into NewTableFromOld
from DamagedTable

Ensuite, déposez / échangez simplement la table endommagée avec la nouvelle, en vous rappelant d'ajouter les contraintes et les index appropriés.

John Sansom
la source
Merci pour la réponse. Votre approche semble bonne, mais l'inquiétude est, étant donné que la table contient 461 millions de lignes de données, quel serait l'impact sur la production lorsque je fais une sélection *? Cela n'acquerrait-il pas un verrou et n'atteindrait-il pas les performances?
Pas si vous utilisez l'indicateur de requête with (nolock) no. Cependant, vous souhaiterez peut-être valider que rien n'a changé entre la table source et la table cible pendant que vous avez pris la copie. De toute façon, cela serait probablement nécessaire lors de la construction de la table si vous n'avez pas empêché l'application d'apporter des modifications. Il y aura une surcharge de performances du disque dans une telle opération.
John Sansom
Personnellement, j'essaierais d'abord cette approche, vous pouvez le faire avec l'option nolock pour les tests, vous pouvez également vérifier le temps requis. Si cela fonctionne comme il se doit, je mettrais alors la base de données en mode mono-utilisateur tout en le faisant à nouveau, pour m'assurer qu'aucun changement ne se produit pendant que le processus est en cours d'exécution. Les temps d'arrêt seront beaucoup plus courts au cours de cette approche, si cela fonctionne.
baldy
Si vous comptez le faire, je vous recommande de créer d'abord la table (en scénarisant la table d'origine). Ensuite, utilisez "INSERT INTO newTable SELECT" vs "SELECT INTO". Vous pouvez rencontrer des problèmes de performances avec un "SELECT INTO".
SQL3D
0

J'essayerais de grouper les données à déposer en premier, puis de les regrouper dans une nouvelle table. SELECT INTO n'est pas approprié (IMO) pour ce nombre d'enregistrements ...

m4rty
la source