sql >> Base de Datos >  >> RDS >> Sqlserver

Uso de la transacción ROLLBACK en SQL Server

Introducción

Muy recientemente, un colega mío acudió a mí desesperado y me dijo que había emitido una declaración de actualización sin una cláusula WHERE en una tabla de aplicaciones clave. Las implicaciones en la parte delantera serían nefastas, por lo que acudió a mí directamente porque necesitaba ayuda urgente para revertir la situación por cualquier medio antes de que los correos electrónicos y la escalada comenzaran a llegar.

Cuando examinamos la situación, encontramos que los cambios no se habían aplicado en la base de datos secundaria. En la mayoría de los casos, el desfase entre nuestra base de datos primaria y secundaria es de veinte minutos (nosotros tenemos un poco de escalonamiento para evitar problemas de rendimiento). Debido a que mi colega solicitó ayuda inmediatamente después de darse cuenta del error, pudimos recuperar los datos de la base de datos secundaria. Describí el valor de tal retraso en este artículo .

Revisión del escenario

El escenario que describí anteriormente no es raro. Una de las razones por las que esto les sucede a los usuarios regulares de SQL Server es que SQL Server usa lo que se llama transacciones implícitas. Las transacciones implícitas están desactivadas de forma predeterminada, lo que significa que SQL Server no espera que emita una declaración COMMIT TRANSACTION al final de cada declaración. En efecto, cada instrucción se confirma automáticamente. Esto es conveniente y ayuda a evitar situaciones en las que las sesiones que aún no se han confirmado terminan bloqueando recursos y afectando el rendimiento. Brent Ozar brinda más detalles sobre las implicaciones de rendimiento de IMPLICIT TRANSACTIONS =ON.

Sin embargo, una pequeña desventaja de esta configuración (TRANSACCIONES IMPLÍCITAS =DESACTIVADA) es que los usuarios no tienen la oportunidad de repensar una declaración y emitir un ROLLBACK, que es muy común en Oracle. La figura 1 muestra las opciones de consulta ANSI disponibles en SQL Server Management Studio.

Fig. 1 Valores predeterminados de ANSI en SQL Server Management Studio

Uso de transacciones implícitas

En esencia, el problema al que nos enfrentamos en esta configuración predeterminada o nuestra herramienta de cliente más deseable es que no podemos ROLLBACK una vez que ejecutamos una instrucción SQL. Podemos eludir esto habilitando TRANSACCIONES IMPLÍCITAS en nuestra sesión. Esto nos dará la oportunidad de ROLLBACK transacciones si es necesario. La Fig. 2 y la Fig. 4 nos muestran que podemos tener esta configuración activada solo para una sesión, aunque esto no elimina el riesgo de que la sesión del usuario bloquee otras si no se emite un ROLLBACK o COMMIT.

Fig. 2 TRANSACCIONES IMPLÍCITAS EN UNA SESIÓN

-- 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 Todas las filas actualizadas

Para ilustrar la solución alternativa descrita aquí, veamos el código SQL en el Listado 1. Supongamos que un usuario regular de SQL Server, un desarrollador junior, ha recibido un conjunto de scripts para ejecutar bajo ciertas condiciones. . En el script, la cláusula WHERE se ha comentado porque se espera que cada vez que ejecuten este script, cambien el predicado. Por supuesto, este es un caso de uso simple y el riesgo se puede abordar de varias maneras, pero solo queremos mostrar la posibilidad de realizar un ROLLBACK.

Recuerde que ya hemos activado la TRANSACCIÓN IMPLÍCITA, por lo que cuando ejecutemos esta declaración, SQL Server esperará que COMPROMETEMOS o RETROCEDAMOS la transacción. La intención del desarrollador es actualizar el countryCode de Joyce Afam a 'SA' ya que emigró a Sudáfrica. La Fig. 3 nos muestra que el desarrollador, al intentar hacer esto, actualizó accidentalmente todas las filas con el valor SA como countryCode . Se dan cuenta de esto y emiten un ROLLBACK.

Fig. 4 Emisión de ROLLBACK

Fig. 5 TRANSACCIONES IMPLÍCITAS ON en otra sesión

Sin embargo, en la otra sesión en la que no activamos las TRANSACCIONES IMPLÍCITAS, encontramos que el desarrollador no puede recuperarse de su error. No pueden emitir con éxito un ROLLBACK en este caso. La recuperación implicaría entonces la restauración de datos.

Fig. 6 ROLLBACK no es posible sin TRANSACCIONES IMPLÍCITAS EN

Uso de transacciones explícitas

Otro enfoque para lograr el mismo efecto es encerrar el DML en una transacción declarando explícitamente BEGIN TRAN. Una vez más, es muy importante completar la transacción, utilizando COMMIT o ROLLBACK. En el contexto de esta discusión, emitimos un ROLLBACK ya que nos damos cuenta de que hay un error en el código.

-- 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

Conclusión

En este artículo, hemos abordado brevemente una buena solución alternativa para crear oportunidades para ROLLBACK y, por lo tanto, mitigar los errores de usuario resultantes de un DML incorrecto. También hemos destacado un riesgo clave de este enfoque, que es el bloqueo involuntario. Un DBA puede iniciar investigaciones sobre la posible presencia de este riesgo consultando sys.dm_tran_session_transactions, sys.dm_tran_locks y objetos de gestión dinámica similares.

Referencias

  1. Corregir la pérdida de datos mediante el trasvase de registros con recuperación retrasada

  2. Establecer transacciones implícitas

  3. Hacer que las transacciones implícitas sean una mala idea

  4. DMV para transacciones