La déconnexion du réseau arrête-t-elle une requête?

13

J'ai récemment exécuté une requête de mise à jour sur 100 000 enregistrements. J'ai réalisé que j'avais fait une erreur pendant l'exécution de la requête et j'ai rapidement débranché le câble réseau.

La requête de mise à jour

  1. arrêter le traitement et complètement annuler?
  2. poursuivre le traitement jusqu'à la fin et valider?
  3. arrêter le traitement et ne mettre à jour qu'une partie des lignes cibles?
robocop
la source
2
une fois qu'une requête atteint le serveur, elle se poursuit, sauf si vous avez annulé la requête sur le serveur.
JP Chauhan
1
Le commentaire de Martin fournit la réponse directe à votre question, robocop. Si le réseau informe SQL Server de la déconnexion avant la fin de l'exécution de votre requête, SQL Server la restaure. Sinon, si la requête se termine avant que SQL Server ne soit informé de la déconnexion du réseau, elle sera validée. En aucun cas (en supposant que vous ayez écrit une seule requête de mise à jour), SQL Server exécutera une mise à jour partielle.
Nick Chammas

Réponses:

22

Comme mentionné par Nick et Martin, le statut final de votre requête dépend de si SQL Server est au courant de votre tirage de câble réseau avant la fin de la requête. De Books Online (bien que je trouve intéressant qu'il y ait des sujets équivalents pour cela en 2000 , 2005 , 2008 et 2008 R2 , mais pas 2012 ou 2014):

Si une erreur empêche la réussite d'une transaction, SQL Server annule automatiquement la transaction et libère toutes les ressources détenues par la transaction. Si la connexion réseau du client à une instance du moteur de base de données est rompue, toutes les transactions en suspens pour la connexion sont annulées lorsque le réseau notifie l'instance de la rupture. Si l'application cliente échoue ou si l'ordinateur client tombe en panne ou est redémarré, cela interrompt également la connexion et l'instance du moteur de base de données annule toutes les connexions en attente lorsque le réseau l'informe de la rupture. Si le client ferme la session sur l'application, toutes les transactions en suspens sont annulées.

(En passant, ce mot connexions dans l'avant-dernière phrase était probablement censé être des transactions . Je ne sais pas comment on annule une connexion.)

De la même manière, SQL Server peut annuler ou rétablir les transactions pendant la récupération après l'arrêt inattendu du serveur, et cela dépendra de l'état de la transaction au moment de l'arrêt. J'ai vu des gens utiliser cette tactique pour réaliser ce que vous tentiez de faire (annuler la (les) transaction (s)) et lorsque le serveur a redémarré une grande partie du travail a simplement été refaite (donc l'effet net de leur réaction de genou était beaucoup plus proche). à zéro que prévu).

Donc, plutôt que d'être soumis à cela, au lieu de faire des choses drastiques dans la panique, comme tirer un câble réseau ou éteindre la machine, je suggère à l'avenir que vous ayez une meilleure discipline pour exécuter des requêtes ad hoc sur des systèmes importants. Par exemple, au lieu de:

UPDATE dbo.sometable 
-- where *oops* I forgot this part

Avoir ceci:

BEGIN TRANSACTION;

UPDATE dbo.sometable
-- where *oops* I forgot this part

-- COMMIT TRANSACTION;
-- ROLLBACK TRANSACTION;

Ensuite, si la mise à jour était en effet correcte, vous pouvez mettre en surbrillance la COMMITpièce et l'exécuter. Si ce n'est pas le cas, vous pouvez calmement mettre en évidence la ROLLBACKpièce et l'exécuter. Vous pouvez même utiliser des compléments tels que SSMS Tools Pack pour modifier votre New Querymodèle afin d'inclure ce passe-partout.

Maintenant, il pourrait toujours vous poser des problèmes dans le cas où vous exécutez la requête et que vous ne validiez ni ne rétrogradiez, car maintenant votre transaction bloque d'autres utilisateurs. Mais cela vaut mieux que de modifier irrévocablement les données.

Et bien sûr, comme toujours, disposez d'une sauvegarde sur laquelle vous pouvez compter.

Aaron Bertrand
la source
5
Il s'agit d'un excellent conseil qui traite de la racine du problème de l'OP, mais il ne répond pas réellement à la question de savoir si la requête a continué de s'exécuter ou non.
Nick Chammas
3
Merci @Nick, ma motivation était d'aborder la cause (qui a suscité la question), pas le symptôme, mais j'ai mis à jour ma réponse.
Aaron Bertrand
8

@Aaron a raison. Créer une transaction avant vos commandes est votre meilleur pari. Si vous ne vous souvenez pas de le faire, une option consiste à entrer dans le Tools-Optionsparamètre et à activer SET IMPLICIT_TRANSACTIONS. Cela démarrera automatiquement une transaction dès que certaines commandes seront exécutées. Cela inclut UPDATE, DELETEetc. Cela semble être une liste assez complète de toute commande qui ferait "change"quelque chose. SELECTest également inclus dans la liste et willdémarre une transaction. Vous pouvez voir une liste complète des commandes qui démarrent une transaction avec ce paramètre ici . Il ne créera pas de transaction si une est déjà démarrée. Maintenant, l'inconvénient est que vous devrez vous souvenir de COMMITtout changement effectué.

REMARQUE: Sur la base de la suggestion de @ Aaron, je vais souligner à nouveau cela.

This is very important!  You will have to remember to COMMIT after any change made!

Fondamentalement, vous échangez en oubliant BEGINune transaction et en gâchant quelque chose, pour oublier COMMITune transaction et la suspendre si vous la laissez ouverte puis partez pour la journée. J'ai testé juste la fermeture d'une fenêtre de requête en pensant qu'elle annulerait ma transaction, mais cela m'a demandé si je voulais valider ou annuler la transaction.

entrez la description de l'image ici

Kenneth Fisher
la source
En fait: SELECT va démarrer une transaction (qui est également documentée dans le lien que vous avez publié)
a_horse_with_no_name
Merci @a_horse_with_no_name d'avoir attrapé ça! Je n'ai pas lu assez attentivement et je sortais d'un vieux souvenir (ce qui était évidemment faux).
Kenneth Fisher
1
Ceci est un article utile, mais il ne répond pas réellement à la question de l'OP de savoir si la requête a continué de s'exécuter ou non.
Nick Chammas
2
Il s'agissait d'un ajout à la réponse de @ Aaron. C'était trop pour mettre un commentaire.
Kenneth Fisher
2

je pense que cela dépend vraiment:

si la commande atteint déjà le serveur avant de débrancher le câble réseau, la commande continuera à s'exécuter normalement.

si vous avez un TransactionScope (utilisé dans .Net, pas sûr d'autres langues) pour encapsuler toutes les commandes de mise à jour, vous ne pouvez probablement arrêter la transaction à être validée que si le transactionScope.Complete () n'a pas été exécuté, mais aucune garantie. .

Rex
la source
2
Vous avez dit "si la commande atteint déjà le serveur avant de débrancher le câble réseau, la commande continuera à s'exécuter normalement." Ceci est contredit par la page SQL Server BOL à laquelle Martin a lié ci-dessus. Voir "Erreurs lors du traitement des transactions" .
Nick Chammas
tu as raison. avec une transaction spécifiée, la commande sera automatiquement annulée. mais comme nous l'avons vu, lorsqu'aucune transaction n'a été spécifiée explicitement, la commande (une mise à jour par lots sans transaction) a été exécutée complètement même si nous avons arrêté notre application au milieu, ce qui a en fait rompu la connexion - mais ce n'est pas vraiment un bon exemple comme le timing n'était probablement pas correct. il est probablement bon de faire des tests pour cela
Rex