Pregunta

Estamos utilizando una base de datos SQL Server 2005 (sin versiones de fila) con una gran instrucción select, y vemos que bloquea la ejecución de otras instrucciones (visto usando sp_who2 ). No me di cuenta de que las declaraciones SELECT podrían causar el bloqueo, ¿hay algo que pueda hacer para mitigar esto?

¿Fue útil?

Solución

SELECT puede bloquear actualizaciones. Un modelo de datos y una consulta correctamente diseñados solo causarán un bloqueo mínimo y no serán un problema. La sugerencia 'habitual' CON NOLOCK es casi siempre la respuesta incorrecta. La respuesta adecuada es ajustar su consulta para que no escanee tablas enormes.

Si la consulta no se puede ajustar, primero debe considerar nivel de AISLAMIENTO INSTANTÁNEO , en segundo lugar, debe considerar usar INSTANTÁNEAS DE LA BASE DE DATOS y la última opción debe estar SUCIA LEA (y es mejor cambiar el nivel de aislamiento en lugar de usar la SUGERENCIA DE NOLOCK). Tenga en cuenta que las lecturas sucias, como su nombre lo indica claramente, devolverán datos inconsistentes (por ejemplo, su hoja total puede estar desequilibrada).

Otros consejos

De documentación :

  Los bloqueos

Shared (S) permiten que las transacciones concurrentes lean (SELECT) un recurso bajo control de concurrencia pesimista. Para obtener más información, consulte Tipos de control de concurrencia . Ninguna otra transacción puede modificar los datos mientras existan bloqueos shared (S) en el recurso. Los bloqueos Shared (S) en un recurso se liberan tan pronto como se completa la operación de lectura, a menos que el nivel de aislamiento de la transacción se establezca en lectura repetible o superior, o se use una pista de bloqueo para retener el compartió (S) bloqueos durante la duración de la transacción.

Un bloqueo compartido es compatible con otro bloqueo compartido o un bloqueo de actualización, pero no con un bloqueo exclusivo.

Eso significa que sus consultas SELECT bloquearán las consultas UPDATE e INSERT y viceversa.

Una consulta SELECT colocará un bloqueo compartido temporal cuando lea un bloque de valores de la tabla y lo eliminará cuando termine de leer.

Mientras exista el bloqueo, no podrá hacer nada con los datos en el área bloqueada.

Dos consultas SELECT nunca se bloquearán entre sí (a menos que sean SELECT FOR UPDATE )

Puede habilitar el nivel de aislamiento SNAPSHOT en su base de datos y usarlo, pero tenga en cuenta que no impedirá que las consultas UPDATE sean bloqueadas por SELECT consultas (que parece ser tu caso).

Sin embargo, evitará que las SELECT sean bloqueadas por UPDATE .

También tenga en cuenta que SQL Server , a diferencia de Oracle , utiliza el administrador de bloqueos y lo mantiene bloqueado en una lista vinculada en memoria.

Eso significa que bajo una carga pesada, el simple hecho de colocar y quitar un bloqueo puede ser lento, ya que la lista vinculada debería estar bloqueada por el hilo de la transacción.

Para realizar lecturas sucias, puede:

 using (new TransactionScope(TransactionScopeOption.Required, 
 new TransactionOptions { 
 IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
 {
 //Your code here
 }

o

SelectCommand = "SELECT * FROM Table1 WITH (NOLOCK) INNER JOIN Table2 WITH (NOLOCK) ..."

recuerda que debes escribir WITH (NOLOCK) después de cada tabla que quieras leer sucio

Puede establecer el nivel de transacción leer sin comprometer

También puede obtener puntos muertos:

" puntos muertos que involucran solo una mesa " http: // sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx

y / o resultados incorrectos:

" Las selecciones en LECTURA COMPROMETIDA y LECTURA REPETIBLE pueden devolver resultados incorrectos. "

http://www2.sqlblog.com/blogs/alexander_kuznetsov/archive/2009/04/10/selects-under-read-committed-and-repeatable-read-may-return -incorrect-results.aspx

Puede usar la sugerencia de tabla WITH (READPAST) . Es diferente al WITH (NOLOCK) . Obtendrá los datos antes de que se inicie la transacción y no bloqueará a nadie. Imagine eso, ejecutó la declaración antes de que se iniciara la transacción.

SELECT * FROM table1  WITH (READPAST)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top