Estoy probando un proceso que elimina muchos, muchos registros a la vez. No puede TRUNCATE TABLE
, porque hay registros allí que deben permanecer.SQL Server Tiempo de espera de bloqueo excedido Eliminación de registros en un bucle
Debido al volumen, he roto la eliminación en un bucle similar a esto:
-- Do not block if records are locked.
SET LOCK_TIMEOUT 0
-- This process should be chosen as a deadlock victim in the case of a deadlock.
SET DEADLOCK_PRIORITY LOW
SET NOCOUNT ON
DECLARE @Count
SET @Count = 1
WHILE @Count > 0
BEGIN TRY
BEGIN TRANSACTION -- added per comment below
DELETE TOP (1000) FROM MyTable WITH (ROWLOCK, READPAST) WHERE MyField = SomeValue
SET @Count == @@ROWCOUNT
COMMIT
END TRY
BEGIN CATCH
exec sp_lock -- added to display the open locks after the timeout
exec sp_who2 -- shows the active processes
IF @@TRANCOUNT > 0
ROLLBACK
RETURN -- ignoring this error for brevity
END CATCH
MiTabla es una tabla agrupada. MyField está en la primera columna del índice agrupado. Indica una agrupación lógica de registros, por lo que MyField = SomeValue
a menudo selecciona muchos registros. No me importa en qué orden se eliminan siempre que se procese un grupo a la vez. No hay otros índices en esta tabla.
He añadido la sugerencia ROWLOCK
para tratar de evitar las escaladas de bloqueo que hemos visto en la producción. Agregué la sugerencia READPAST
para evitar borrar registros bloqueados por otros procesos. Eso nunca debería suceder, pero estoy tratando de estar seguro.
Problema: a veces este ciclo llega a un tiempo de espera de bloqueo 1222 "Excedido el tiempo de espera de solicitud de bloqueo excedido" cuando es el único en ejecución.
Estoy seguro de que no hay otra actividad en este sistema mientras estoy probando este proceso, porque es mi propio cuadro de desarrollador, nadie más está conectado, no hay otros procesos ejecutándose en él y el generador de perfiles no muestra actividad.
Puedo volver a ejecutar el mismo script un segundo más tarde y se retoma donde lo dejó, borrando felizmente registros-- hasta el siguiente tiempo de espera de bloqueo.
He intentado un BEGIN TRY
/BEGIN CATCH
para ignorar el error 1222 y volver a intentar la eliminación, pero falla de nuevo inmediatamente con el mismo error de tiempo de espera de bloqueo. También falla nuevamente si agrego un pequeño retraso antes de volver a intentar.
Supongo que los tiempos de espera de bloqueo se deben a algo así como una división de página, pero no estoy seguro de por qué esto entraría en conflicto con la iteración actual del ciclo. La declaración de eliminación anterior ya debería haberse completado, y pensé que eso significaba que las divisiones de página también habían finalizado.
¿Por qué el ciclo DELETE golpea un tiempo de espera de bloqueo contra sí mismo?
¿Hay alguna manera en que el proceso pueda evitar este tiempo de espera de bloqueo o detectar que es seguro reanudar?
Esto es en SQL Server 2005.
- EDITAR -
he añadido el evento Lock: Tiempo de espera para el generador de perfiles. Es el tiempo de espera en un PageLock durante el borrado:
Event Class: Lock:Timeout
TextData: 1:15634 (one example of several)
Mode: 7 - IU
Type: 6 - PAGE
DBCC página Informes de estas páginas se encuentran fuera del rango de la base de datos maestra (ID 1).
- EDIT 2 -
he añadido un BEGIN TRY
/BEGIN CATCH
y corrió un exec sp_lock
en el bloque catch.Esto es lo que vi:
spid dbid ObjId IndId Type Resource Mode Status
19 2 1401108082 1 PAG 1:52841 X GRANT (tempdb.dbo.MyTable)
19 2 1401108082 0 TAB IX GRANT (tempdb.dbo.MyTable)
Me 2 1401108082 0 TAB IX GRANT (tempdb.dbo.MyTable)
Me 1 1115151018 0 TAB IS GRANT (master..spt_values) (?)
SPID 19 es un TASK MANAGER de SQL Server. ¿Por qué uno de estos administradores de tareas estaría adquiriendo bloqueos en MyTable?
¿Ha intentado trazar los diversos eventos de bloqueo en SQL Trace para ver si se puede deshacer lo que está pasando? –
Acabo de hacer, gracias por mencionar eso. Agregué la información de tiempo de espera de bloqueo anterior. No estoy seguro de qué está bloqueado exactamente. –
Otra edición: agregó algo de información de sp_lock inmediatamente después del tiempo de espera de bloqueo. –