2011-03-28 16 views
6

Actualmente estoy realizando algunos experimentos en una base de datos de SQL Server 2008. Más específicamente, tengo una aplicación JDBC que utiliza cientos de hilos concurrentes para ejecutar miles de tareas, cada una de las cuales se ejecuta la siguiente consulta en la base de datos:SQL Server 2008: Obteniendo deadlocks ... sin bloqueos

UPDATE from Table A where rowID='123' 

Sin embargo, yo estoy poniendo un montón de errores de punto muerto (Excepción de SQL 1205) cada vez que configuro el nivel de aislamiento como superior a READ_UNCOMMITTED. ¡Sucede incluso si configuro bloqueo de fila, bloqueo de tabla y sugerencias exclusivas de bloqueo! E incluso en el aislamiento de instantáneas, que no utiliza bloqueos, sigo teniendo errores de interbloqueo.

Ejecuté un rastreo a través del Analizador de SQL para obtener el gráfico de interbloqueo cuando esto sucede, pero no fue de mucha utilidad. Mostraba el proceso de la víctima, conectado a un "grupo de hilos", conectado a cientos de otros procesos. Puede verificarlo aquí:

http://i.stack.imgur.com/7rlv3.jpg

¿Alguien tiene alguna pista de por qué está sucediendo esto? Me he estado volviendo loco en los últimos días tratando de resolverlo. Mi hipótesis actual es que se trata de algo relacionado con los subprocesos de trabajo disponibles en mi instancia de base de datos, la cantidad de memoria disponible o algo que no está relacionado con los bloqueos de nivel de consulta reales.

Gracias!

+0

[¿Ya lo ha visto?] (Http://blogs.msdn.com/b/bartd/archive/2008/09/24/today-s-annoyingly-unwieldy-term-intra-query-parallel-thread- deadlocks.aspx) ¿Su instrucción de actualización tiene un plan paralelo? –

+0

¿Y está diciendo que estos bloqueos ** nunca ** ocurren cuando 'READ_UNCOMMITTED' está en vigor? No es en absoluto obvio para mí cómo eso afectaría la declaración 'update' que se muestra. –

+0

¡Guau! ¡No esperaba una respuesta tan abrumadora en tan poco tiempo! Los bloqueos continúan en READ_UNCOMMITTED, pero solo cuando hay muchos, muchos, muchos más hilos concurrentes (alrededor de 1000). Me disculpo por la vaguedad. – akwok

Respuesta

1

Los bloqueos/bloqueos como estos son extraños y apuntan a algo fuera del servidor SQL. Por lo que vale, tuvimos muchos problemas de interbloqueo que resultaron ser un cuello de botella en el disco.

Le sugiero que ejecute perfmon (y, obviamente, después de eso, muchas otras herramientas) y vea cómo le está yendo.

1

No se puede hacer nada en SQL Server sin cerraduras - incluso la consulta más básica cubiertas con NOLOCK declaraciones emitirá un bloqueo de esquema y probablemente algunos bloqueos de página en el mínimo.

Para resolver un interbloqueo, debe obtener un rastreo de interbloqueo T1204 (consulte Deadlock Troubleshooting, Part 1 para obtener más información) que enumerará los bloqueos y objetos exactos que intervienen en el interbloqueo. Esta información debería ser suficiente (con el cantidad de rasguños en la cabeza) exactamente lo que salió mal.

Cambio del nivel de aislamiento sin comprender plenamente la razón detrás de un callejón sin salida parece un poco peligroso para mí ...

Como el presentimiento de que esto me recuerda a un problema que tuve hace unos años - es la declaración supercondenación UPDATE contra una declaración SELECT? (La traza T1024 le dirá esto) ¿Y tiene un índice no agrupado en rowID? Si es así, puede echar un vistazo al this MSDN article, específicamente el Ejemplo 6: Índices no agrupados. De lo contrario, eche un vistazo a ese artículo, ya que puede ayudar a explicar algunos otros escenarios relevantes de interbloqueo, también publique los resultados del rastreo T1024 si necesita ayuda para analizarlo.

6

Ha encontrado una bestia más esotérica: un punto muerto de recursos. Lo que tiene allí es un subproceso que no puede generar tareas secundarias (sys.dm_os_tasks) para ejecutar su trabajo porque todos los trabajadores (sys.dm_os_workers) están ocupados. A su vez, los trabajadores ocupados ejecutan tareas que la víctima bloquea, probablemente en cerraduras ordinarias.

Hay dos lecciones que veo aquí para llevar a casa:

1) El ACTUALIZACIÓN informados está tratando de ir en paralelo. Si la actualización es exactamente como la publicó, significa una y única cosa: no hay índice en rowId.

2) Ha rebotado en el techo superior ajustado por max worker threads ajuste. No es de extrañar, considerando que abuse de los hilos en el cliente (hundreds of concurrent threads to execute thousands of task) y multiplique esto en el servidor debido a un paralelismo no deseado.

Un diseño razonable sería utilizar la ejecución asíncrono (BeginExecuteNonQuery) en una conexión verdaderamente asíncrono (AsynchronousProcessing=true) y utilizar un conjunto de peticiones pendientes para que no se supera un cierto umbral. Sin embargo, lo más probable es que pase un lote completo de valores de actualización por table valued parameter y luego actualice un conjunto completo o filas, por lotes, en una sola declaración. Entiendo que todos mis enlaces son para .Net, no para Java, no me importa, usted mismo puede extraer la funcionalidad Java equivalente.

Aunque es interesante que hayas descubierto un punto muerto tan esotérico, solo aparece porque tu diseño, bueno ... apesta.

+1

Tendría +1 para un análisis brillante ... pero lo atenué con -1 para, digamos, ¿entrega? Omisión de 2 palabras más o menos habría leído ... ¿más agradable? – RichardTheKiwi

+1

Gracias por la respuesta, Remus. Entiendo que el diseño apesta, ¡pero está hecho a propósito! Estoy trabajando en un proyecto que se supone que muestra que 1.) existen diferentes anomalías de lectura dependiendo del tipo de nivel de aislamiento elegido y para mostrar 2.) éxitos de rendimiento empírico para elegir un nivel de aislamiento que restrinja la concurrencia más de lo necesario. En cualquier caso, tus comentarios tienen sentido, y lo investigaré un poco más; al menos, usted fue capaz de darme una dirección para seguir leyendo en :-) – akwok

+0

@akwok: Ya veo. Tenga en cuenta que la ACTUALIZACIÓN debe encontrar primero las filas para actualizar y luego actualizarlas. La parte 'buscar' * está * influenciada por el nivel de aislamiento. Incluso REPEATABLE_READ puede elegir escanear a un nivel de bloqueo de alta granularidad (página, tabla). Lo segundo a tener en cuenta es que la parte 'actualizaciones' entrará en conflicto con otra actualización en todos los niveles de aislamiento, incluida la instantánea. Además, las actualizaciones de * diferentes * filas entrarán en conflicto debido a las colisiones hash: http://rusanu.com/2009/05/29/lockres-collision-probability-magic-marker-16777215/ –

Cuestiones relacionadas