tengo un procedimiento almacenado que realiza una combinación de TableB
-TableA
:SQL Server Deadlock Fix: ¿Forzar orden de unión o volver a intentarlo automáticamente?
SELECT <--- Nested <--- TableA
Loop <--
|
---TableB
Al mismo tiempo, en una transacción, las filas se insertan en TableA
, y luego en TableB
.
Esta situación es a veces causando bloqueos, ya que el procedimiento almacenado seleccione agarra filas de TableB, mientras que la inserción añade filas a TableA, y luego cada uno quiere que el otro para dejar de lado la otra tabla:
INSERT SELECT
========= ========
Lock A Lock B
Insert A Select B
Want B Want A
....deadlock...
lógica requiere la INSERT
añadir filas primera a Un, y luego a B, mientras que personalmente no me importa el orden en que SQL Server realiza su unen - siempre y cuando se une.
La recomendación común para la fijación de interbloqueos es garantizar que todos accedan a los recursos en el mismo orden. Pero en este caso, el optimizador de SQL Server me dice que el orden opuesto es "mejor". Puedo forzar otra orden de unión y tener una consulta de peor rendimiento.
¿Pero debería?
¿Debo anular el optimizador, ahora y para siempre, con un orden de combinación que quiero que use?
¿O debería simplemente atrapar error error nativo 1205 y reenviar la instrucción select?
La pregunta no es cuánto empeoraría la consulta al anular el optimizador y hacer algo no óptimo. La pregunta es: ¿es mejor volver a intentar automáticamente, en lugar de ejecutar peores consultas?
Remus, retrying lee tiene perfecto sentido, pero reintentar escrituras automáticamente después de bloqueos lleva a la pérdida de actualizaciones. Cuando escribe y se convierte en una víctima de punto muerto, es probable que los datos que va a tocar hayan sido modificados por otra persona. No deberíamos reescribir automáticamente en tales casos. Deberíamos volver a leer los datos posiblemente modificados, y considerar nuevamente si queremos guardar. ¿Tiene sentido? –
@AlexKuznetsov: Eso es absurdo, si una transacción se escribe correctamente (es decir, atómicamente), entonces, ¿cómo podría reintentarse si resulta en una actualización perdida? Le doy este +1, definitivamente es la respuesta correcta. No puede detener cada punto muerto, es solo parte del ruido de fondo con semántica ÁCIDA. – Aaronaught
@Alex, @ Aaro: En realidad ambos tienen razón. Por "reintentar" me refiero a "leer el estado actual, aplicar cambios, escribir nuevo estado". Para aplicaciones de procesamiento automatizado, este es un patrón muy fácil de lograr. Sin embargo, para las aplicaciones interactivas del usuario, esto puede ser más difícil y, a menudo, la acción adecuada es retrasar la "escritura" al volver a leer el estado actual y volver a mostrarlo al usuario, para que pueda confirmar que los cambios aplicados tiene sentido en el nuevo estado/contexto, y creo que esto es lo que Alex tenía en mente. Por lo tanto, la acción correcta depende de cada caso. –