2009-07-23 18 views
52

Entiendo cómo una transacción puede ser útil para coordinar un par de actualizaciones. Lo que no entiendo es incluir declaraciones únicas en las transacciones, que es el 90% de lo que he visto en mi vida. De hecho, en el código de la vida real, es más común en mi experiencia encontrar una serie de transacciones lógicamente relacionadas, cada una envuelta en su propia transacción, pero el todo no está envuelto en una transacción.¿Qué hace una transacción en torno a una sola declaración?

En MS-SQL, ¿hay alguna ventaja de incluir selecciones simples, actualizaciones únicas, inserciones simples o eliminaciones únicas en una transacción?

Sospecho que esta es la programación supersticiosa.

Respuesta

45

No hace nada. Todas las sentencias SQL individuales, (con raras excepciones como Inserciones masivas sin registro o Truncar tabla) son automáticamente "En una transacción", explícitamente lo diga o no ... (incluso si insertan, actualizan o eliminan millones de filas) .

EDIT: @ basado en el comentario de Phillip abajo ... En las versiones actuales de SQL Server, insertos Incluso a granel y TRUNCATE TABLE no escribir algunos datos en el registro de la transacción, aunque no tanto como lo hacen otras operaciones. La distinción fundamental desde una perspectiva transaccional es que en estos otros tipos de operaciones, los datos en las tablas de la base de datos que se modifican no están en el registro en un estado que le permite deshacerse.

Todo esto significa que los cambios que la declaración hace a los datos en la base de datos se registran en el registro de transacciones para que puedan deshacerse si la operación falla.

La única función que proporcionan los comandos "Comenzar transacción", "Confirmar transacción" y "Realizar transacción Rollback" es permitirle colocar dos o más instrucciones SQL individuales en la misma transacción.

EDITAR: (para reforzar las marcas comenta ...) SÍ, esto podría atribuirse a la programación "supersticiosa", o podría ser una indicación de un malentendido fundamental de la naturaleza de las transacciones de bases de datos. Una interpretación más caritativa es que es simplemente el resultado de una aplicación durante la consistencia que es inadecuado y un ejemplo más de Emerson eufemismo que:

Una consistencia estúpida es el duende de las mentes pequeñas,
adoraban a poco estadistas y filósofos y teólogos

+3

Deberías afirmar, sí, esta es una programación supersticiosa. =) –

+0

@Charles, ¿qué pasa con MySQL? – Pacerier

+1

@Pacerier, no hablo con fluidez MySQL, pero me quedaría atónito si su producto se comportara de manera diferente a este respecto de otros productos relacionales. Uno de los productos de base de datos no relacionales más nuevos, como noSQL, podría funcionar bajo un paradigma diferente, pero apostaría a que MySQL es el mismo. –

2

Cuando inicia una transacción explícita y emite un DML, los recursos bloqueados por la declaración permanecen bloqueados, y los resultados de la declaración no son visibles desde fuera de la transacción hasta que la confirme o restituya manualmente.

Esto es lo que puede o no necesitar.

Por ejemplo, es posible que desee mostrar los resultados preliminares al mundo exterior sin dejar de mantenerlos bloqueados.

En este caso, se empieza otra transacción que coloca una solicitud de bloqueo antes de que el primero se compromete, evitando así la condición de carrera

transacciones implícitas están comprometidos o se deshace immediatamente después de la declaración DML completa o falla.

+0

Ah, diferencia sutil. Pero en realidad no es un beneficio de las transacciones explícitas, creo que el tiempo extra que las transacciones de declaración única de bloqueo de transacciones explícitas serían una clara situación de pérdida/pérdida - menor rendimiento y menor concurrencia, aunque probablemente por milisegundos. – MatthewMartin

+1

@MatthewMartin: no dije nada sobre los beneficios o inconvenientes, solo le expliqué la diferencia. Las transacciones no son todo sobre el rendimiento. Por ejemplo, es posible que desee mostrar los resultados preliminares al mundo exterior mientras mantiene un bloqueo sobre ellos. En este caso, se inicia otra transacción que colocará una solicitud de bloqueo antes de que el primero se comprometa, evitando así la condición de carrera. En este caso, aún necesita ajustar esta única declaración en una transacción. – Quassnoi

+0

SQL Server no admite transacciones anidadas genuinas. Comenzar otra es una mala idea. http://www.sqlskills.com/BLOGS/PAUL/post/A-SQL-Server-DBA-myth-a-day-(2630)-nested-transactions-are-real.aspx – IamIC

5

Como dijo Charles Bretana, "no hace nada", nada más que lo que ya está hecho.

¿Has oído hablar de los requisitos "ACID" de una base de datos relacional? Esa "A" significa Atomic, lo que significa que o bien la instrucción funciona en su totalidad, o no - y mientras la declaración se está realizando, no otras consultas se pueden hacer en los datos afectados por esa consulta. BEGIN TRANSACTION/COMMIT "amplía" esta funcionalidad de bloqueo al trabajo realizado por varias instrucciones, pero no agrega nada a declaraciones individuales.

Sin embargo, el registro de transacciones de base de datos es siempre escrito a cuando se modifica una base de datos (insertar, actualizar, eliminar). Esta no es una opción, un hecho que tiende a irritar a la gente. Sí, hay rareza con inserciones masivas y modos de recuperación, pero todavía se escribe.

Voy a poner nombre a los niveles de aislamiento aquí también. Alterar con esto afectará a los comandos individuales, pero al hacerlo no hará que una consulta envuelta en una transacción declarada realice una consulta diferente a una consulta "independiente". (Tenga en cuenta que pueden ser muy poderosos y muy peligrosos con las transacciones declaradas en varias declaraciones). Tenga en cuenta también que "nolock" hace no se aplica a inserciones/actualizaciones/eliminaciones - esas acciones siempre requieren bloqueos.

+0

@Philip, Thx, al investigar su comentario, descubrí que las cosas han cambiado para 'Bulk Insert' desde la última vez que revisé esta funcionalidad (SQL 7 o SQL2k) ... –

+0

Pero dos consultas independientes ejecutadas en un solo comando sin una transacción explícita del código se ejecutarían como dos transacciones implícitas en la base de datos con todo lo que significa en términos de niveles de aislamiento y datos sucios/escritos. – Henrik

2

Una posible excusa es que esa declaración única podría hacer que un montón de otros SQL se ejecuten a través de desencadenantes, y que están protegiendo contra algo que va mal allí, aunque esperaría que cualquier DBMS tuviera el sentido común para utilizar transacciones implícitas de la misma manera ya.

La otra cosa que puedo pensar es que algunas API le permiten desactivar la confirmación automática, y el código está escrito por si alguien lo hace.

+1

Los desencadenadores de SQL Server se ejecutan dentro de una transacción implícita del código DML que los inició. Y sí, MS SQL le permite desactivar la confirmación automática. Ver: http://msdn.microsoft.com/en-us/library/aa259220(SQL.80).aspx –

3

Para mí, envolver una sola declaración en una transacción significa que tengo la capacidad de deshacerla si, por ejemplo, olvido una cláusula WHERE al ejecutar una declaración UPDATE manual y única. Me ha salvado un par de veces.

p. Ej.

-------------------------------------------------------------- 
CREATE TABLE T1(CPK INT IDENTITY(1,1) NOT NULL, Col1 int, Col2 char(3)); 
INSERT INTO T1 VALUES (101, 'abc'); 
INSERT INTO T1 VALUES (101, 'abc'); 
INSERT INTO T1 VALUES (101, 'abc'); 
INSERT INTO T1 VALUES (101, 'abc'); 
INSERT INTO T1 VALUES (101, 'abc'); 
INSERT INTO T1 VALUES (101, 'abc'); 
INSERT INTO T1 VALUES (101, 'abc'); 

SELECT * FROM T1 


-------------------------------------------------------------- 
/* MISTAKE SCENARIO  (run each row individually) */ 
-------------------------------------------------------------- 
BEGIN TRAN YOUR_TRANS_NAME_1; /* open a trans named YOUR_TRANS_NAME_1 */ 
    UPDATE T1 SET COL2 = NULL; /* run some update statement */ 
    SELECT * FROM T1;  /* OOPS ... forgot the where clause */ 
ROLLBACK TRAN YOUR_TRANS_NAME_1; /* since it did bad things, roll it back */ 
    SELECT * FROM T1;  /* tans rolled back, data restored. */ 



-------------------------------------------------------------- 
/* NO MISTAKES SCENARIO (run each row individually) */ 
-------------------------------------------------------------- 

BEGIN TRAN YOUR_TRANS_NAME_2; 
    UPDATE T1 SET COL2 = 'CBA' WHERE CPK = 4; /* run some update statement */ 
    SELECT * FROM T1;    /* did it correctly this time */ 

COMMIT TRAN YOUR_TRANS_NAME_2   /* commit (close) the trans */ 

-------------------------------------------------------------- 

DROP TABLE T1 

-------------------------------------------------------------- 
+2

Tal vez mi pregunta no estaba clara. Me refería al código como: begin tran; update foo set col1 = null; cometer tran; Que se ejecuta como un solo lote. Este es un patrón muy común en varias bases de código que he mantenido y también es común ver cuando trazas el sql que está emitiendo una aplicación existente. Está describiendo un proceso interactivo que se realiza en dos pasos discretos. – MatthewMartin

Cuestiones relacionadas