2009-04-27 14 views
15

Estamos tratando de tener una tabla transaccional que solo tome nuevos registros insertados regularmente.¿Por qué SQL Server 2008 bloquea los SELECT en transacciones largas INSERT?

Esta tabla simple requiere que agreguemos continuamente nuevos registros a lo largo del tiempo. Se espera que el volumen de transacciones en esta tabla sea bastante alto, y también puede haber importaciones periódicas por lotes de transacciones (> 1000) que pueden tardar varios segundos en completarse.

A partir de estos datos, a continuación, hacemos un conjunto de declaraciones de selección que agrupan columnas diferentes para devolver los valores requeridos.

A partir de nuestras pruebas iniciales, hemos encontrado un cuello de botella relacionado con SQL Server que bloquea nuestro SELECT cuando se encuentra en medio de una transacción de INSERTS.

A continuación se muestra un ejemplo simple que se puede ejecutar para ilustrar el problema.

- Simple DB Tabla

create table LOCK_TEST (
LOCK_TEST_ID int identity , 
AMOUNT int); 

- Ejecutar esta consulta en la ventana 1

begin tran 
insert into LOCK_TEST (AMOUNT) values (1); 
WAITFOR DELAY '00:00:15' ---- 15 Second Delay 
insert into LOCK_TEST (AMOUNT) values (1); 
commit 

- En la Consulta 2 plazo esto en paralelo

select SUM(AMOUNT) 
from LOCK_TEST; 

Yo esperaría Consulta 2 para volver inmediatamente, con 0 hasta que se complete la consulta 1, y luego mostrar 2. Nunca queremos ver 1 como resultado de la segunda consulta.

Las respuestas que hemos analizado se relacionan con WITH (NOLOCK) en la instrucción select. Pero esto infringe los límites transaccionales, y la información devuelta puede ser de naturaleza financiera y no deseamos ver ningún detalle sin compromiso en nuestras consultas.

Mi problema parece estar en el lado INSERT ...
¿Por qué bloquean el INSERT la instrucción SELECT a pesar de que no es la modificación de los datos existentes?

Pregunta de puntos extra: ¿Es esta una "característica" de SQL Server, o la encontraríamos en otros sabores de bases de datos también?

ACTUALIZACIÓN Ahora he tenido tiempo de encontrar una base de datos local de Oracle y ejecutar la misma prueba simple. Este pase de prueba es como esperaba.

Es decir, que se puede ejecutar la consulta con la frecuencia que yo quiero, y volverá nula hasta que la primera transacción se confirma, entonces vuelve 2.

¿Hay una manera de hacer el trabajo de SQL Server como este? o ¿tenemos que movernos a Oracle?

+0

¿Qué índices tiene en estas tablas? ¿tiene mantenimiento de índice regular? –

+0

No hay índices en este momento. Vea el ejemplo simple enumerado en esta publicación, nada más que la simple tabla de 2 columnas, inserción básica y selección se utilizan para volver a crear este problema. – stevemac

Respuesta

12

este comportamiento de bloqueo es una característica de SQL Server. Con 2005 y versiones superiores, puede usar row level versioning (que es lo que se usa por defecto en Oracle) para lograr el mismo resultado & sin bloquear las selecciones. Esto ejerce una presión adicional sobre tempdb porque tempdb mantiene el control de versiones a nivel de fila, así que asegúrese de acomodarse a esto. Para hacer SQL se comportan de la manera que usted quiere que ejecuta:

ALTER DATABASE MyDatabase 
SET ALLOW_SNAPSHOT_ISOLATION ON 

ALTER DATABASE MyDatabase 
SET READ_COMMITTED_SNAPSHOT ON 
+0

http://stackoverflow.com/a/4118803/2319909 –

4

Este es un comportamiento completamente estándar en SQL Server y Sybase (al menos).

Los cambios de datos (Insertar, actualizar, eliminar) requieren exclusive locks.esto hace que los lectores sean bloqueados:

Con una (X) bloqueo exclusivo, no hay otras transacciones puede modificar los datos; lea operaciones solo pueden realizarse con el uso de la sugerencia NOLOCK o lea nivel de aislamiento no confirmado.

Con SQL Server 2005 y versiones posteriores, introdujeron el aislamiento de instantáneas (también conocido como control de versiones de filas). De MS BOL: Understanding Row Versioning-Based Isolation Levels. Esto significa que un lector tiene los últimos datos confirmados, pero si luego desea escribir de nuevo, por ejemplo, puede encontrar que los datos son incorrectos porque cambiaron en la transacción de bloqueo.

Ahora, esta es la razón por la cual la mejor práctica es mantener las transacciones cortas. Por ejemplo, sólo procesar lo que necesita para comenzar entre/COMMIT, no envíe mensajes de correo electrónico de los desencadenantes etc.

Editar:

bloqueo como esto sucede todo el tiempo en SQL Server. Sin embargo, el bloqueo durante demasiado tiempo se convierte en bloqueo que reduce el rendimiento. Demasiado tiempo es subjetivo, obviamente.

+0

La transacción es corta, pero el volumen de las mismas causa bloqueos que no deberían requerirse en absoluto. Ver el comentario sobre la pregunta sobre Oracle. – stevemac

+0

Vaya a Oracle si lo desea. Si puede trasladarse a Oracle simplemente entonces sospecho que su SQL no es óptimo, está haciendo un viaje de ida y vuelta desde un cliente a otro, o algo que está causando demasiado bloqueo. – gbn

+1

¿Cómo puede un ejemplo tan simple no ser óptimo? Del simple ejemplo provisto, todavía bloquea. ¿Puede sugerir cómo cambio el ejemplo proporcionado para hacerlo óptimo? Tenga en cuenta que NUNCA habrá actualizaciones de estos datos, solo nuevas inserciones. – stevemac

1

Esto también existe en MySQL. Aquí está la lógica detrás de esto: si realiza un SELECCIONAR en algunos datos, espera que funcione en un conjunto de datos actualizado. Es por eso que INSERT resulta en un bloqueo a nivel de tabla (esto es, a menos que el motor pueda realizar el bloqueo a nivel de fila, como innodb). Hay formas de desactivar este comportamiento, para que pueda hacer "lecturas sucias", pero todas son software (o incluso motor de base de datos) específico.

+1

Estoy de acuerdo, pero también quiero que reconozca las transacciones. Desde mi punto de vista, los nuevos registros (los de la transacción) no existen, y posiblemente nunca lo harán. Por qué la base de datos bloquea datos que (desde mi punto de vista) no existen parece estar mal. Entiendo que si estaba actualizando datos en un lugar y SELECTándolos desde otro lugar, podría esperar la actualización, pero quiero control de eso ... Especialmente con INSERTAR. Parece que Oracle hace lo que yo esperaba. Todavía estoy tratando de averiguar si SQL Server puede. – stevemac

1

También me encontré con este problema. Después de la investigación, parecía ser que no eran los datos los que se bloqueaban per se, sino el índice agrupado que se estaba modificando como resultado del inserto. Como el índice agrupado reside en las páginas de datos, las filas de datos asociadas también están bloqueadas.

Cuestiones relacionadas