La grande requête de suppression semble avoir gelé


10

Nous avons exécuté une requête de suppression sur une base de données avec 1,8 milliard de lignes. Cette suppression supprimerait 1,2 milliard de lignes.

Avec le recul, nous aurions divisé cette requête en 100 m à la fois, mais nous sommes dans une position où elle fonctionne depuis 24 heures et le fichier journal est à 2 To, ce qui semble être la taille maximale autorisée pour un fichier journal.

La base de données est en mode de récupération SIMPLE.

Y a-t-il une sauvegarde de cette requête? Ou devons-nous simplement redémarrer SQL Server et voir ce qui se passe? La base de données sera-t-elle inutilisable? Y a-t-il quelque chose que nous puissions faire pour tuer cela aussi proprement que possible?


L'avez-vous exécuté à partir de SSMS? Il suffit de l'annuler. L'annulation prendra un certain temps. Comme depuis longtemps qu'il a fonctionné. Tu dois être patient.
paparazzo

1
@Graeme D'après notre expérience avec des bases de données de milliards d'enregistrements (nous en exécutons quelques-unes), il est parfois plus rapide d'enregistrer les enregistrements restants de la table des victimes, de les tronquer, de les supprimer, de renommer les enregistrements enregistrés au nom d'origine, puis de restaurer les index, le cas échéant. .
Anton Krouglov

1
Une fois que vous avez effacé ce spid, je recommanderais des lots beaucoup plus petits que 100m, je fais généralement de 100k à 1m. Utilisez également votre clé primaire comme clause WHERE pour sélectionner les enregistrements à supprimer, si possible.
BradC

Tronquer est votre ami lorsque vous supprimez de grandes quantités de données et essayez d'éviter les problèmes de journal.
Jeff.Clark

Réponses:


14

Tout d'abord, vérifiez le journal des erreurs SQL pour voir s'il atteint réellement une taille maximale pour le journal. Si c'est le cas, la requête n'a aucun espoir de se terminer, elle est probablement déjà dans un état de restauration.

Même si c'est le cas, je préfère toujours tuer le spid manuellement (utilisez sp_who2ou sp_WhoIsActivepour trouver le spid, puis faites un kill 59ou autre). Vous ne pouvez pas non plus vérifier l'état de restauration, sauf si vous effectuez un KILL explicite, consultez ce fil connexe .

Comme il s'agit d'une suppression, et non d'une mise à jour ou d'un insert, vous pouvez être très chanceux et constater qu'il annule immédiatement. Sinon, il faudra peut-être autant de temps (ou plus) pour revenir en arrière que pour arriver à ce point.

Pour voir l'état de restauration, utilisez

kill 59 with statusonly

Malheureusement, j'ai trouvé que cela ne montre souvent rien d'utile, juste un "0% terminé". Dans ce cas, vous devrez utiliser sp_who2et regarder l'IO et le CPU pour voir s'il fait toujours quelque chose.

Concernant le redémarrage, c'est un risque grave. Si le spid est activement rétrogradé (CPU et IO changent), le redémarrage de SQL ne mettra la base de données hors ligne que jusqu'à ce que la restauration soit complètement terminée (heures et heures). Mais , si le CPU et les IO ne bougent pas , cela peut en fait l'effacer immédiatement. De toute façon, c'est un risque.

Une dernière option, si les choses sont particulièrement désastreuses: si vous avez une sauvegarde juste avant le début de la suppression (et qu'il n'y a pas eu d'autres mises à jour de la base de données) , le moyen le plus rapide de récupérer peut être de simplement supprimer la base de données, de redémarrer SQL et restauration à partir d'une sauvegarde.

Si vous ne pouvez pas supprimer la base de données (ou si vous avez déjà redémarré l'instance et que le journal des erreurs sql prévoit un temps de récupération de 24 heures), puis arrêtez les services SQL, supprimez les fichiers MDF et LDF du disque, démarrez SQL, supprimez la base de données (fantôme) et restaurer à partir de la sauvegarde.

Évidemment, vous ne tenteriez que si c'était une base de données de traitement principale avec laquelle les utilisateurs n'interagissaient pas.


3
Bon conseil, sur l'option de restauration. Effrayant comme l'enfer, mais toujours de bons conseils.
Max Vernon

2
Oui, nous avons eu un DBA redémarrer une instance dans cette condition, ce qui nous a obligés à choisir entre deux très mauvaises options: être en panne pendant 18-24 heures, ou perdre des données en reculant avant le début de la requête. L'entreprise a choisi de revenir en arrière.
BradC

1
Nous avons une sauvegarde complète à partir du 4 mars que nous restaurerons en dernier recours si le redémarrage ne fonctionne pas. Heureusement, c'est une DB suffisamment statique que nous voulions simplement réduire. Merci pour les commentaires, très utiles
Graeme

4
@Graeme - FYI - au lieu d'essayer de supprimer 1,2 milliard de lignes, faites une copie de la structure de la table, copiez les lignes que vous souhaitez conserver dans la nouvelle table, puis supprimez l'ancienne table. Si vous ajoutez une nouvelle question demandant comment le faire, je peux vous montrer une manière très simple qui est beaucoup plus rapide que de supprimer 1,2 milliard de lignes.
Max Vernon

Ma réponse suppose que la base de données est en mode de récupération SIMPLE. S'il est en mode COMPLET, vous devrez également gérer les énormes sauvegardes du journal de transfert.
BradC

8

NE REDÉMARREZ PAS SERVEUR SQL. Cela ne fera que prolonger votre agonie puisque la récupération aura lieu, ce qui annulera ou recommencera toutes les transactions non terminées, y compris votre suppression.

La suppression de la session qui exécute la suppression entraînera une restauration, ce qui prendra également beaucoup de temps.

Vous souhaitez consulter la requête suivante pour voir l'état de l'opération:

SELECT des.session_id 
    , des.host_name
    , des.login_name
    , der.command
    , der.estimated_completion_time
    , der.blocking_session_id
    , der.last_wait_type
    , der.percent_complete
    , der.start_time
    , der.status
    , der.wait_resource
    , der.wait_type
    , der.wait_time
FROM sys.dm_exec_sessions des
    INNER JOIN sys.dm_exec_requests der ON des.session_id = der.session_id
WHERE des.session_id <> @@SPID
    AND des.is_user_process = 1
ORDER BY des.session_id;

La percent_completecolonne et celles qui en dépendent, telles que estimated_completion_time, ne sont remplies que pour les opérations suivantes:

ALTER INDEX REORGANIZE
AUTO_SHRINK option with ALTER DATABASE
BACKUP DATABASE
DBCC CHECKDB
DBCC CHECKFILEGROUP
DBCC CHECKTABLE
DBCC INDEXDEFRAG
DBCC SHRINKDATABASE
DBCC SHRINKFILE
RECOVERY
RESTORE DATABASE
ROLLBACK
TDE ENCRYPTION

Vous ne verrez donc cette colonne que si vous avez déjà annulé l'instruction delete et qu'elle est annulée, ou si vous avez déjà redémarré SQL Server et qu'il est en cours de récupération.

Si la blocking_session_idcolonne contient un nombre, cela indique qu'une autre session bloque l'opération de suppression. Si cette session a bloqué l'opération de suppression depuis qu'elle a démarré, vous pourrez peut-être annuler l'opération sans avoir à effectuer de restauration.


Bonnes requêtes, mais il semble peu probable que le journal soit devenu énorme si la suppression avait été bloquée.
BradC

4
Oui. J'essaie juste d'expliquer légèrement la sortie. Les futurs lecteurs peuvent également voir cela. En fait, je doute que nous entendions le PO dans un proche avenir. Il est probablement assez occupé.
Max Vernon
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.