2012-09-26 105 views
48

Me pregunto cuál es la ventaja de utilizar SELECT WITH (NOLOCK) en una tabla si las únicas otras consultas que afectan a esa tabla son SELECT consultas.Comprensión de bloqueos de SQL Server en las consultas SELECT

¿Cómo lo maneja SQL Server? ¿Una consulta SELECT bloquearía otra consulta SELECT?

Estoy usando SQL Server 2012 y un Linq-to-SQL DataContext.

(EDIT)

Sobre el rendimiento:

  • ¿Un segundo SELECT tener que esperar para una primera SELECT para terminar si se utiliza un SELECT bloqueado?
  • Versus a SELECT WITH (NOLOCK)?

Gracias.

Respuesta

111

Un SELECT en SQL Server va a colocar un bloqueo compartido en una fila de la tabla - y un segundo SELECT también requeriría un bloqueo compartido, y esos son compatibles entre sí.

Así que nadie SELECT no puede bloquear otro SELECT.

Para lo que se utiliza la sugerencia de consulta WITH (NOLOCK) es para poder leer datos que están en proceso de ser insertados (por otra conexión) y que aún no se han confirmado.

Sin esa sugerencia de consulta, una SELECT podría ser bloqueado lectura de una tabla de una instrucción en curso INSERT (o UPDATE) que coloca un bloqueo exclusivo en filas (o, posiblemente, una mesa entera), hasta que la transacción de que la operación se ha cometido (o revertido).

problema de la WITH (NOLOCK) pista es: es posible que la lectura de filas de datos que no se van a insertar en absoluto, al final (si la transacción se deshace INSERT) - para que su ejemplo informe puede mostrar datos que nunca se han comprometido realmente con la base de datos.

Hay otra sugerencia de consulta que podría ser útil: WITH (READPAST). Esto instruye al comando SELECT para omitir cualquier fila que intente leer y que esté bloqueada exclusivamente. El SELECT no se bloqueará, y no leerá ningún dato "sucio" no comprometido, pero podría omitir algunas filas, p. no mostrar todas sus filas en la tabla.

+1

¡Buena respuesta, muchas gracias! ¿Habría un impacto (en cientos de consultas 'SELECT') para usar' WITH (NOLOCK) 'sin razón? –

+1

Usamos con nolock en el 99.5% de nuestras selecciones, no es broma. Si un administrador está actualizando un registro de usuario, no desea que el informe se quede allí y espere a que termine toda la transacción distribuida. Entonces, sus datos antiguos aparecen en el informe. ¿A quien le importa? Si el informe se ejecutó un segundo antes, es la misma información que habría estado allí con rowlock. El único lugar que le preocupa es la información que aún no está comprometida. Si muestra "pedidos en la última hora", eso podría ser un problema, pero un pequeño problema en comparación con las ganancias de velocidad/concurrencia. –

+2

También desde que se lanzó un 'informe' como ejemplo, los informes son típicamente por un período de tiempo que no son los últimos 5 minutos. Informes de datos del mes pasado con nolock: bueno, no es como si los datos se revertieran un mes después. –

1

seleccionar sin bloqueo: seleccionará los registros que pueden o no insertarse. leerás datos sucios.

por ejemplo, digamos que una transacción inserta 1000 filas y luego falla.

cuando seleccione - obtendrá las 1000 filas.

+0

Pero, ¿qué pasa si no se pretende insertar ningún registro en esa tabla, ¿NO SIGUE SIENDO CERRADO? –

+0

no, no lo es. ya que read usa un bloqueo compartido que puede ser adquirido por más de 1 sesión. no hay forma de obtener datos sucios. –

+0

Y en un POV de rendimiento? –

6

En mi trabajo, tenemos un sistema muy grande que se ejecuta en muchas PC al mismo tiempo, con tablas muy grandes con cientos de miles de filas y, a veces, muchos millones de filas.

Cuando realiza una SELECCIÓN en una tabla muy grande, digamos que desea conocer cada transacción que un usuario ha realizado en los últimos 10 años, y la clave principal de la tabla no está construida de manera eficiente, la consulta puede tardar varios minutos en ejecutarse.

Entonces, nuestra aplicación me podría ejecutar en muchas PC de usuario al mismo tiempo, accediendo a la misma base de datos. Entonces, si alguien intenta insertar en la tabla que está leyendo el otro SELECT (en páginas que SQL está tratando de leer), entonces puede ocurrir un BLOQUEO y las dos transacciones se bloquean entre sí.

Tuvimos que agregar un "NINGÚN BLOQUEO" a nuestra declaración SELECCIONAR, porque era una SELECCIÓN enorme sobre una mesa que muchos usuarios utilizan mucho al mismo tiempo y teníamos CERROJOS todo el tiempo.

No sé si mi ejemplo es lo suficientemente claro? Este es un ejemplo de la vida real.

+0

Gracias por el ejemplo, pero solo me pregunto sobre las consultas SELECT que afectan a otras consultas SELECT (en esa misma tabla) .. –

+1

No lo harán, pero una instrucción select podría ser parte de la transacción que incluye una actualización . Actualizar tbl establecer x = (seleccionar max (y) desde tbl) donde z = (seleccionar min (a) desde tbl). Si tiene una selección simultánea z de tbl, las demás selecciones no lo están bloqueando, pero la actualización sí lo está. –

+0

Tuve exactamente este problema que una selección de ejecución larga estaba bloqueando mis inserciones – nojetlag

22

En cuanto al rendimiento, sigue centrándose en la selección.
Compartido no bloquea lecturas.
Actualización de bloques de bloqueo compartidos.
Si tiene cientos de bloqueos compartidos, llevará una actualización un tiempo obtener un bloqueo exclusivo, ya que debe esperar a que los bloqueos compartidos se eliminen.

Por defecto, seleccionar (leer) toma un bloqueo compartido.
Los bloqueos compartidos (S) permiten que las transacciones simultáneas lean (SELECCIONE) un recurso.
Un bloqueo compartido como ningún efecto en otros selecciona (1 o un 1000).

La diferencia es cómo se actualiza o inserta la función nolock frente a los efectos de bloqueo compartido.

Ninguna otra transacción puede modificar los datos mientras existen bloqueos compartidos (S) en el recurso.

¡Un bloqueo compartido bloquea una actualización!
Pero nolock no bloquea una actualización.

Esto puede tener un gran impacto en el rendimiento de las actualizaciones. También impacta insertos.

Dirty read (nolock) suena sucio. Nunca obtendrás datos parciales. Si una actualización cambia a John a Sally, nunca lo conseguirás.

Uso mucho los bloqueos compartidos para concurrencia. Los datos están desactualizados tan pronto como se leen. Una lectura de John que cambia a Sally en el siguiente milisegundo es información obsoleta. Una lectura de Sally que se revierte John en el siguiente milisegundo son datos obsoletos. Eso es en el nivel de milisegundo. Tengo un cargador de datos que demora 20 horas para ejecutarse si los usuarios toman bloqueos compartidos y 4 horas para ejecutarlo, ya que los usuarios no tienen bloqueo. Los bloqueos compartidos en este caso hacen que los datos estén atascados 16 horas.

No use nolocks mal. Pero ellos tienen un lugar. Si va a cortar un cheque cuando un byte se establece en 1 y luego lo establece en 2 cuando se corta el cheque, no es un momento para un nolock.

+1

Gracias. Vemos características de rendimiento similares. Nuestro sitio no se ejecutará si necesitamos bloqueos para lecturas, y el impacto de no tenerlo en la mayoría de los casos es simplemente insignificante. –

+0

@BrianWhite Gracias. Alguien lo entiende Y tomo muchos bloqueos de tabla en actualización e inserción. Entrar, terminarlo y salir es mi enfoque. – Paparazzi

+1

Dirty read (nolock) suena sucio. Nunca obtendrás datos parciales. Si una actualización cambia a John a Sally, nunca lo conseguirás. - Leímos a John ¿verdad? – MonsterMMORPG

2

El SELECT WITH (NOLOCK) permite la lectura de datos no confirmados, lo que es equivalente a tener el nivel de aislamiento READ UNCOMMITTED establecido en su base de datos. La palabra clave NOLOCK permite un control más detallado que establecer el nivel de aislamiento en toda la base de datos.

Wikipedia tiene un artículo útil: Wikipedia: Isolation (database systems)

También se analiza en profundidad en otros artículos stackoverflow.

+0

Gracias rghome por la información adicional que ha proporcionado. –

+0

Es por eso que prefiero usar la sugerencia 'READUNCOMMITTED' (un alias para' NOLOCK'), * cuando * such es un caso de uso válido. Al hacerlo, la operación real, que * no es * realmente "sin bloqueos", es menos incierta. – user2864740

7

Tengo que agregar un comentario importante. Todos mencionan que NOLOCK solo lee datos sucios. Esto no es preciso También es posible que obtenga la misma fila dos veces o que toda la fila se omita durante la lectura. La razón es que puede solicitar algunos datos al mismo tiempo cuando SQL Server está reequilibrando b-tree.

Comprobar otros hilos

https://stackoverflow.com/a/5469238/2108874

http://www.sqlmag.com/article/sql-server/quaere-verum-clustered-index-scans-part-iii.aspx)

Con la sugerencia NOLOCK (o ajuste el nivel de aislamiento de la sesión para READ) informarle de SQL Server que no lo hace esperar consistencia, entonces no hay garantías. Tenga en cuenta que los "datos inconsistentes" no solo significan que es posible que vea cambios no confirmados que luego se retrotraeron, o cambios de datos en un estado intermedio de la transacción. También significa que en una consulta simple que escanea todos los datos de tabla/índice, SQL Server puede perder la posición de escaneo, o puede terminar obteniendo la misma fila dos veces.

Cuestiones relacionadas