2012-09-24 5 views
8

Estoy ejecutando varias consultas SQL de larga ejecución como parte de un módulo de informes. Estas consultas se construyen dinámicamente en tiempo de ejecución. Dependiendo de la entrada del usuario, pueden ser de declaración única o múltiple, tener uno o más parámetros y operar en una o más tablas de base de datos; en otras palabras, su formulario no puede anticiparse fácilmente.Utilice SqlTransaction & IsolationLevel para una operación de lectura prolongada?

Actualmente, sólo estoy ejecutar estas declaraciones en una ordinaria SqlConnection, es decir

using (SqlConnection cn = new SqlConnection(ConnectionString)) { 
    cn.Open(); 
    // command 1 
    // command 2 
    // ... 
    // command N 
} 

Debido a que estas consultas (realmente consultar lotes) puede tomar un tiempo para ejecutar, me preocupa acerca de los bloqueos en las tablas sosteniendo lee/escribe para otros usuarios. No es un problema si los datos de estos informes cambian durante la ejecución del lote; las consultas de informes nunca deben tener prioridad sobre otras operaciones en esas tablas, ni deben bloquearlas.

Para la mayoría de las operaciones de larga ejecución/declaraciones múltiples que implican modificar datos, usaría transacciones. La diferencia aquí es que estas consultas de informes no modifican ningún dato. ¿Sería correcto incluir estas consultas de informe en un SqlTransaction para controlar su nivel de aislamiento?

es decir:

using (SqlConnection cn = new SqlConnection(ConnectionString)) { 
    cn.Open(); 

    using (SqlTransaction tr = cn.BeginTransaction(IsolationLevel.ReadUncommitted)) { 
     // command 1 
     // command 2 
     // ... 
     // command N 

     tr.Commit(); 
    } 
} 

Sería esto lograr mi resultado deseado? ¿Es correcto realizar una transacción, aunque no se hayan modificado los datos? ¿Hay otro enfoque?

+0

¿Los informes tienen que ser [correcta] (http://blogs.msdn.com/b/sqlcat/archive/2007/02/01/previously-committed-rows-might- be-missed-if-nolock-hint-is-used.aspx) o no? –

+0

@RemusRusanu Los informes proporcionan una instantánea instantánea de los datos durante un largo período de tiempo; no es necesario que tengan en cuenta los cambios que pueden ocurrir a mitad de la transacción. Es probable que el usuario ejecute varias veces las consultas subyacentes en una sucesión breve, y el usuario no esperará que los resultados sean idénticos cada vez. –

+1

Este es exactamente el tipo de informes que se ven afectados (mal) por lecturas sucias. Los recuentos y agregados saltarán aleatoriamente hacia arriba y hacia abajo y los datos dentro de una sola ejecución (un informe) no serán consistentes (p. Ej., Suma de adeudo! = Suma de crédito). Sus usuarios perderán confianza en el informe, ya que parecerá producir datos aleatorios. ¿Ha considerado en su lugar ['SNAPSHOT'] (http://msdn.microsoft.com/en-us/library/ms345124 (v = sql.90) .aspx)? –

Respuesta

5

Otro enfoque podría ser para emitir, en contra de la conexión:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 

que logra la misma intención, sin jugar con una transacción. O puede usar la sugerencia WITH(NOLOCK) en las tablas de su consulta, que tiene la ventaja de no cambiar la conexión en absoluto.

Es importante destacar que en cuenta que (inusualmente): embargo se pone cambiado (transacción y transacción alcance, explícita SET, etc), el nivel de aislamiento es no reajuste entre los usos de la misma conexión subyacente cuando lo recoges de la piscina. Esto significa que si su código cambia el nivel de aislamiento (directa o indirectamente), entonces ninguno de su código sabe cuál es el nivel de aislamiento de una nueva conexión es:

using(var conn = new SqlConnection(connectionString)) { 
    conn.Open(); 
    // isolation level here could be **ANYTHING**; it could be the default 
    // if it is a brand new connection, or could be whatever the last 
    // connection was when it finished 
} 

que hace que el WITH(NOLOCK) muy tentador.

+0

.... explicaciones demasiado cortas de sus sugerencias. – ulrichb

+1

Guau, gracias por la advertencia sobre establecer el nivel de aislamiento ... que podría ser peligroso. –

+0

Al establecer el nivel de aislamiento mediante BeginTransaction, ¿evitamos el problema de "nivel de aislamiento no restablecido entre conexiones" que mencionó? Si es así, ¿hay alguna desventaja al usar una transacción? – digEmAll

1

Estoy de acuerdo con Marc, pero alternativamente puede usar la sugerencia de consulta NOLOCK en las tablas afectadas. Esto le daría la capacidad de controlarlo en una tabla por nivel de tabla.

El problema al ejecutar cualquier consulta sin tomar bloqueos compartidos es que usted se deja abierto a resultados "no deterministas", y las decisiones comerciales no deben tomarse con estos datos.

Un mejor enfoque puede ser investigar los niveles de aislamiento SNAPSHOT o READ_COMMITED_SNAPSHOT. Estos le brindan protección contra anomolías transaccionales sin tomar bloqueos. La compensación es que aumentan IO contra TempDB. Cualquiera de estos niveles se puede aplicar a la sesión como Marc sugirió o la tabla como sugerí.

Esperanza esto ayuda

Cuestiones relacionadas