Bloqueos en Base de Datos

05/03/2008 - 10:11 por Manuel | Informe spam
El escenario donde se produce esta situación es la siguiente:

Servidor Windows 2000
SQL Server 2000 con Service pack 4

Se producen interbloqueos entre dos procedimientos (en la franja horaria de
gran actividad de la aplicación, pues en otros horarios los procesos tardan
menos de un segundo) que atacan a la misma tabla. La tabla consta de 34
campos y unos 60000 registros. Posee una primary key (campo1) y los
siguientes índices:

Indice1: campo2, campo3, campo4, campo5
Indice2: campo4, campo5, campo6
Indice3: campo7

Los procedimientos que se bloquean entre sí son:

Procediemiento1:

UPDATE TABLA
SET campo7=NULL, campo6=NULL, campo5='T'
FROM T_CLASIFICACION_BLOQUEO WHERE campo7=@variable
AND campo5='Valor'

Procediemiento2:

Hace una SELECT y luego un UPDATE, en función de ciertas condiciones, el
WHERE cambia ligeramente:

Caso1.

SELECT Campo1, campoX, campoY, …
FROM TABLA WITH(NOLOCK)
WHERE campo2=@variable1
AND campo3=@variable2
AND campoX is not null
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
ORDER BY campoX, campo1


begin transaction
UPDATE TABLA
SET campo7=CONVERT(VARCHAR(8), @variable5)), campo4='ValorX', campo6
=GETDATE()
FROM M_TABLA_MAESTRO
INNER JOIN TABLA ON M_TABLA_MAESTRO.campoA = TABLA.campoA
WHERE campo2=@variable1
AND campo3=@variable2
AND campoX is not null
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
AND COD_ESTADO not in ('ValorA','ValorB', 'ValorC')

if @@error<>0
begin
rollback transaction
return
end
else
commit transaction

Caso2. (en el WHERE no aparece el campo campoX)

SELECT Campo1, campoX, campoY, …
FROM TABLA WITH(NOLOCK)
WHERE campo2=@variable1
AND campo3=@variable2
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
ORDER BY campoX, campo1


begin transaction
UPDATE TABLA
SET campo7=CONVERT(VARCHAR(8), @variable5)), campo4='ValorX', campo6
=GETDATE()
FROM M_TABLA_MAESTRO
INNER JOIN TABLA ON M_TABLA_MAESTRO.campoA = TABLA.campoA
WHERE campo2=@variable1
AND campo3=@variable2
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
AND COD_ESTADO not in ('ValorA','ValorB', 'ValorC')

if @@error<>0
begin
rollback transaction
return
end
else
commit transaction

Caso 3 (en el WHERE se fuerza al campo campos a un valor determinado)

SELECT Campo1, campoX, campoY, …
FROM TABLA WITH(NOLOCK)
WHERE campo2=@variable1
AND campo3=@variable2
AND campoX =@variableX
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
ORDER BY campoX, campo1


begin transaction
UPDATE TABLA
SET campo7=CONVERT(VARCHAR(8), @variable5)), campo4='ValorX', campo6
=GETDATE()
FROM M_TABLA_MAESTRO
INNER JOIN TABLA ON M_TABLA_MAESTRO.campoA = TABLA.campoA
WHERE campo2=@variable1
AND campo3=@variable2
AND campoX is not null
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
AND COD_ESTADO not in ('ValorA','ValorB', 'ValorC')

if @@error<>0
begin
rollback transaction
return
end
else
commit transaction

Los registros que se sacan en las actualizaciones o consultas no llegan casi
nunca a la centena.
¿Cuál seria la mejor manera de optimización para minimizar las colisiones
entre procedimientos?
 

Leer las respuestas

#1 Luis Tarzia
05/03/2008 - 19:03 | Informe spam
Esta bien que se bloqueen si ambos hacen update,el update va a bloquear
hasta terminar,quiza te convenga poner transacciones y aparte el select
puede ser with nolock pero te puede traer cualquier cosa.
"Manuel" escribió en el mensaje
news:
El escenario donde se produce esta situación es la siguiente:

Servidor Windows 2000
SQL Server 2000 con Service pack 4

Se producen interbloqueos entre dos procedimientos (en la franja horaria


de
gran actividad de la aplicación, pues en otros horarios los procesos


tardan
menos de un segundo) que atacan a la misma tabla. La tabla consta de 34
campos y unos 60000 registros. Posee una primary key (campo1) y los
siguientes índices:

Indice1: campo2, campo3, campo4, campo5
Indice2: campo4, campo5, campo6
Indice3: campo7

Los procedimientos que se bloquean entre sí son:

Procediemiento1:

UPDATE TABLA
SET campo7=NULL, campo6=NULL, campo5='T'
FROM T_CLASIFICACION_BLOQUEO WHERE campo7=@variable
AND campo5='Valor'

Procediemiento2:

Hace una SELECT y luego un UPDATE, en función de ciertas condiciones, el
WHERE cambia ligeramente:

Caso1.

SELECT Campo1, campoX, campoY, .
FROM TABLA WITH(NOLOCK)
WHERE campo2=@variable1
AND campo3=@variable2
AND campoX is not null
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
ORDER BY campoX, campo1


begin transaction
UPDATE TABLA
SET campo7=CONVERT(VARCHAR(8), @variable5)), campo4='ValorX', campo6
=GETDATE()
FROM M_TABLA_MAESTRO
INNER JOIN TABLA ON M_TABLA_MAESTRO.campoA = TABLA.campoA
WHERE campo2=@variable1
AND campo3=@variable2
AND campoX is not null
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
AND COD_ESTADO not in ('ValorA','ValorB',


'ValorC')

if @@error<>0
begin
rollback transaction
return
end
else
commit transaction

Caso2. (en el WHERE no aparece el campo campoX)

SELECT Campo1, campoX, campoY, .
FROM TABLA WITH(NOLOCK)
WHERE campo2=@variable1
AND campo3=@variable2
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
ORDER BY campoX, campo1


begin transaction
UPDATE TABLA
SET campo7=CONVERT(VARCHAR(8), @variable5)), campo4='ValorX', campo6
=GETDATE()
FROM M_TABLA_MAESTRO
INNER JOIN TABLA ON M_TABLA_MAESTRO.campoA = TABLA.campoA
WHERE campo2=@variable1
AND campo3=@variable2
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
AND COD_ESTADO not in ('ValorA','ValorB',


'ValorC')

if @@error<>0
begin
rollback transaction
return
end
else
commit transaction

Caso 3 (en el WHERE se fuerza al campo campos a un valor determinado)

SELECT Campo1, campoX, campoY, .
FROM TABLA WITH(NOLOCK)
WHERE campo2=@variable1
AND campo3=@variable2
AND campoX =@variableX
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
ORDER BY campoX, campo1


begin transaction
UPDATE TABLA
SET campo7=CONVERT(VARCHAR(8), @variable5)), campo4='ValorX', campo6
=GETDATE()
FROM M_TABLA_MAESTRO
INNER JOIN TABLA ON M_TABLA_MAESTRO.campoA = TABLA.campoA
WHERE campo2=@variable1
AND campo3=@variable2
AND campoX is not null
AND campoY=@variable3
AND (campoZ<=@variable4
AND campo4='Valor1'
AND (campo5 = 'Valor2' OR (campo5='Valor3' AND campo7=CONVERT(VARCHAR(8),
@variable5)))
OR campoXX=@variable6
OR (campoXX IS NULL AND campoYY ='Valor4'))
AND COD_ESTADO not in ('ValorA','ValorB',


'ValorC')

if @@error<>0
begin
rollback transaction
return
end
else
commit transaction

Los registros que se sacan en las actualizaciones o consultas no llegan


casi
nunca a la centena.
¿Cuál seria la mejor manera de optimización para minimizar las colisiones
entre procedimientos?

Preguntas similares