Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Utilisation de la transaction ROLLBACK dans SQL Server

Introduction

Très récemment, un de mes collègues est venu me voir en désespoir de cause en affirmant qu'il avait émis une instruction de mise à jour sans clause WHERE sur une table d'application clé. Les implications sur le front-end seraient désastreuses, alors il est venu me voir directement parce qu'il avait un besoin urgent d'aide pour inverser la situation par tous les moyens avant que les e-mails et l'escalade ne commencent à affluer.

Lorsque nous avons examiné la situation, nous avons constaté que les modifications n'avaient pas été appliquées dans la base de données secondaire. Dans la plupart des cas, le décalage entre nos bases de données primaires et secondaires est de vingt minutes (nous avons un peu d'étalement pour éviter les problèmes de performances). Parce que mon collègue a demandé de l'aide immédiatement après avoir réalisé l'erreur, nous avons pu récupérer les données de la base de données secondaire. J'ai décrit la valeur d'un tel délai dans cet article .

Examen du scénario

Le scénario que j'ai décrit ci-dessus n'est pas rare. L'une des raisons pour lesquelles cela arrive aux utilisateurs réguliers de SQL Server est que SQL Server utilise ce qu'on appelle des transactions implicites. Les transactions implicites sont désactivées par défaut, ce qui signifie que SQL Server ne s'attend pas à ce que vous émettiez une instruction COMMIT TRANSACTION à la fin de chaque instruction. En effet, chaque instruction est validée automatiquement. Ceci est pratique et permet d'éviter les situations dans lesquelles des sessions qui n'ont pas encore été validées finissent par bloquer les ressources et affecter les performances. Brent Ozar donne plus de détails sur les implications de performance de IMPLICIT TRANSACTIONS =ON.

Cependant, un petit inconvénient de cette configuration (IMPLICIT TRANSACTIONS =OFF) est que les utilisateurs n'ont pas la possibilité de repenser une instruction et d'émettre un ROLLBACK, ce qui est très courant dans Oracle. La figure 1 montre les options de requête ANSI disponibles dans SQL Server Management Studio.

Fig. 1 Valeurs par défaut ANSI dans SQL Server Management Studio

Utiliser des transactions implicites

Essentiellement, le problème auquel nous sommes confrontés dans cette configuration par défaut ou notre outil client le plus souhaitable est que nous ne pouvons pas ROLLBACK une fois que nous avons exécuté une instruction SQL. Nous pouvons contourner cela en activant les TRANSACTIONS IMPLICITES dans notre session. Cela nous donnera la possibilité d'ANNULER les transactions si nous en avons besoin. Les Fig. 2 et Fig. 4 nous montrent que nous ne pouvons activer ce paramètre que pour une seule session, même si cela n'élimine pas le risque que la session de l'utilisateur en bloque d'autres si un ROLLBACK ou un COMMIT n'est pas émis.

Fig. 2 TRANSACTIONS IMPLICITES SUR en une seule session

-- Listing 1: UPDATE Table TAB2 with IMPLICIT_TRANSACTIONS ON
SET IMPLICIT_TRANSACTIONS ON

DECLARE @IMPLICIT_TRANSACTIONS VARCHAR(3) = 'OFF';  
IF ( (2 & @@OPTIONS) = 2 ) SET @IMPLICIT_TRANSACTIONS = 'ON';  
SELECT @IMPLICIT_TRANSACTIONS AS IMPLICIT_TRANSACTIONS;

USE KTrain
GO
SELECT * FROM Tab2;
GO

UPDATE TAB2
SET countryCode='SA'
-- WHERE fname='Joyce';
GO
SELECT * FROM Tab2;
GO

Fig. 3 Toutes les lignes mises à jour

Pour illustrer la solution de contournement décrite ici, examinons le code SQL dans la liste 1. Supposons qu'un utilisateur régulier de SQL Server, un développeur junior, a reçu un ensemble de scripts à exécuter sous certaines conditions . Dans le script, la clause WHERE a été commentée car on s'attend à ce qu'à chaque fois qu'ils exécutent ce script, ils modifient le prédicat. Bien sûr, il s'agit d'un cas d'utilisation simple et le risque peut être traité de plusieurs manières, mais nous souhaitons simplement montrer la possibilité d'effectuer un ROLLBACK.

Rappelez-vous que nous avons déjà activé la TRANSACTION IMPLICITE, donc lorsque nous exécutons cette instruction, SQL Server s'attendra à ce que nous COMMIT ou ROLLBACK la transaction. L'intention du développeur est de mettre à jour le countryCode de Joyce Afam à « SA » depuis qu'elle a immigré en Afrique du Sud. La figure 3 nous montre que le développeur, en essayant de le faire, a accidentellement mis à jour toutes les lignes avec la valeur SA comme countryCode . Ils le remarquent et émettent un ROLLBACK.

Fig. 4 Emission de ROLLBACK

Fig. 5 TRANSACTIONS IMPLICITES SUR une autre session

Cependant, dans l'autre session dans laquelle nous n'avons pas activé les TRANSACTIONS IMPLICITES, nous constatons que le développeur est incapable de se remettre de son erreur. Ils ne peuvent pas émettre avec succès un ROLLBACK dans ce cas. La récupération impliquerait alors la restauration des données.

Fig. 6 ROLLBACK impossible sans TRANSACTIONS IMPLICITES ON

Utiliser des transactions explicites

Une autre approche pour obtenir le même effet consiste à inclure le DML dans une transaction en indiquant explicitement BEGIN TRAN. Encore une fois, il est très important de terminer la transaction - en utilisant COMMIT ou ROLLBACK. Dans le cadre de cette discussion, nous émettons un ROLLBACK puisque nous réalisons qu'il y a une erreur dans le code.

-- Listing 2: UPDATE Table TAB2 with Explicit Transaction

BEGIN TRAN 
GO
USE KTrain
GO
SELECT * FROM Tab2;
GO

UPDATE TAB2
SET countryCode='GH'
-- WHERE fname='Joyce';
GO
SELECT * FROM Tab2;
GO

ROLLBACK;

SELECT * FROM Tab2;
GO

- Listing 3: Corrected UPDATE Statement

BEGIN TRAN 
GO
USE KTrain
GO
SELECT * FROM Tab2;
GO

UPDATE TAB2
SET countryCode='SA'
WHERE fname='Joyce';
GO
SELECT * FROM Tab2;
GO

Conclusion

Dans cet article, nous avons brièvement abordé une bonne solution de contournement pour créer des opportunités de ROLLBACK et ainsi atténuer les erreurs des utilisateurs résultant d'un mauvais DML. Nous avons également mis en évidence un risque clé de cette approche, qui est le blocage par inadvertance. Un DBA peut commencer des investigations sur la présence possible de ce risque en interrogeant sys.dm_tran_session_transactions, sys.dm_tran_locks , et objets de gestion dynamique similaires.

Références

  1. Résoudre la perte de données à l'aide de l'envoi de journaux avec récupération différée

  2. Définir les transactions implicites

  3. Définir les transactions implicites comme une mauvaise idée

  4. DMV pour les transactions