2011-12-05 32 views
10

Tenemos un problema con un punto muerto y publiqué este question.Servidor SQL, insertar una fila bloquea la tabla completa

Con un poco de ayuda y mucha búsqueda yo mismo creo que descubrí lo que está pasando. Para resolver los interbloqueos sin controlar la escalada de bloqueo, necesito entender por qué el servidor sql bloquea toda la tabla al insertar una fila.

Aquí es mi instrucción de inserción (con variables cambiado el nombre):

DECLARE 
    @Type1 INT = 11, 
    @Type2 INT = NULL, 
    @Value1 VARCHAR(20) = '0', 
    @Value2 VARCHAR(20) = '0', 
    @Value3 VARCHAR(20) = '0', 
    @Value4 VARCHAR(20) = '0', 
    @Date1 DATETIME = '2011-11-25', 
    @Date2 DATETIME = '2011-11-25', 
    @Value5 NVARCHAR(50) = '', 
    @Value6 NVARCHAR(50) = '', 
    @Type3 INT = NULL, 
    @Value7 VARCHAR(20) = '4', 
    @Type4 INT = 4, 
    @Type5 INT = 15153, 
    @Type6 INT = 3, 
    @Type7 INT = 31, 
    @Type8 INT = 5976, 
    @Type9 INT = 5044, 
    @Guid1 UNIQUEIDENTIFIER = 'a8293471-3hb4-442b-844f-44t92f17n67s', 
    @Value8 VARCHAR(200) = '02jfgg55savolhffr1mkjf45', 
    @value10 INT = 1, 
    @Option2 BIT = 0, 
    @Value9 VARCHAR(20) = null, 
    @Option1 BIT = 0 

insert into dbo.OurTable 
(
    Type1 
    ,Type2 
    ,Value1 
    ,Value2 
    ,Value3 
    ,Value4 
    ,Date1 
    ,Date2 
    ,Value5 
    ,Value6 
    ,Type3 
    ,Value7 
    ,Type4 
    ,Type5 
    ,Type6 
    ,Type7 
    ,Type8 
    ,Type9 
    ,value10 
    ,Col1 
    ,Col2 
    ,Col3 
    ,Col4 
    ,Value8 
    ,Option2 
    ,Value9 
) 
values 
(
    CASE 
     WHEN [dbo].[GetType](@Type1, null) = 6 AND @Option1 = 1 AND [dbo].[GetType](@Type4, 0) <> 1 
     THEN 7 
     ELSE [dbo].[GetType](@Type1, null) 
    END 
    ,[dbo].[GetType](@Type2, null) 
    ,case when @Value1 = 'null' then null else CAST(@Value1 as numeric(18, 6)) end 
    ,case when @Value2 = 'null' then null else CAST(@Value2 as numeric(18, 6)) end 
    ,case when @Value3 = 'null' then null else CAST(@Value3 as numeric(18, 6)) end 
    ,case when @Value4 = 'null' then null else CAST(@Value4 as numeric(18, 6)) end 
    ,[dbo].[GetDate](@Date1, null) 
    ,[dbo].[GetDate](@Date2, null) 
    ,@Value5 
    ,@Value6 
    ,[dbo].[GetType](@Type3, null) 
    ,case when @Value7 = 'null' then null else CAST(@Value7 as numeric(18, 6)) end 
    ,[dbo].[GetType](@Type4, null) 
    ,@Type6 
    ,case when LOWER(@Type7) = 'null' then null else @Type7 end 
    ,@Type5 
    ,@Type9 
    ,@Type8 
    ,@value10 
    ,GETDATE() 
    ,GETDATE() 
    ,[dbo].[GetGuid](@Guid1) 
    ,[dbo].[GetGuid](@Guid1) 
    ,@Value8 
    ,@Option2 
    ,case when @Value9 = 'null' then null else CAST(@Value9 as int) end 
) 

Si me quedo esta declaración en una transacción y luego volver a consultar sys.dm_tran_locks antes de comprometerse consigo 10233 filas que pertenecen a esa sesión.

SELECT * 
FROM sys.dm_tran_locks l 
WHERE l.resource_type <> 'DATABASE' AND l.request_session_id = 65 

65 es el ID de sesión de mi ventana actual durante la prueba.

También si miro el bloqueo de la mesa (que es la causa de mi punto muerto) puedo ver que pone un candado X en la mesa OurTable.

resource_type resource_associated_entity_id Name resource_lock_partition request_mode request_type request_status 
OBJECT 290100074 OurTable 0 X LOCK GRANT 
OBJECT 290100074 OurTable 1 X LOCK GRANT 
OBJECT 290100074 OurTable 2 X LOCK GRANT 
OBJECT 290100074 OurTable 3 X LOCK GRANT 
OBJECT 290100074 OurTable 4 X LOCK GRANT 
OBJECT 290100074 OurTable 5 X LOCK GRANT 
OBJECT 290100074 OurTable 6 X LOCK GRANT 
OBJECT 290100074 OurTable 7 X LOCK GRANT 
OBJECT 290100074 OurTable 8 X LOCK GRANT 
OBJECT 290100074 OurTable 9 X LOCK GRANT 
OBJECT 290100074 OurTable 10 X LOCK GRANT 
OBJECT 290100074 OurTable 11 X LOCK GRANT 
OBJECT 290100074 OurTable 12 X LOCK GRANT 
OBJECT 290100074 OurTable 13 X LOCK GRANT 
OBJECT 290100074 OurTable 14 X LOCK GRANT 
OBJECT 290100074 OurTable 15 X LOCK GRANT 

No sé si esto se hace debido a lock escalation o si se solicita un bloqueo exclusivo sobre la mesa desde el principio. De todos modos, esto me causa problemas con los bloqueos.

La razón por la que hay 16 filas de bloqueo en una sola tabla se debe a lock partitioning.

Mi pregunta es, ¿por qué no solicitar un bloqueo exclusivo intención (IX) en la mesa? En cambio, solicita un bloqueo exclusivo. ¿Cómo evito esto? No recibo consejos de ajuste en el afinador, ya lo he intentado.

EDIT Hay un disparador de inserción en OurTable que actualiza un campo en OurTable3. Se ve así:

UPDATE OurTable3 SET Date1 = NULL 
    FROM OurTable3 as E 
     JOIN OurTable2 as C on E.Id = C.FKId 
     JOIN OurTable as ETC on ETC.FKId = C.Id 
      AND (ETC.Date2 IS NULL OR CAST(ETC.Date2 AS DATE) > E.Date1) 
      AND ETC.Type1 = 1 

Como se puede ver que no se actualiza OurTable pero OurTable consultar con el fin de actualizar la fila correcta en OurTable3.

+1

¿Has mirado el nivel de aislamiento de transacción? http://msdn.microsoft.com/en-us/library/ms173763.aspx – dash

+1

¿Es posible que todas esas funciones hagan referencia a "OurTable" también? Ejecuta MUCHAS funciones allí ... – JNK

+1

¿Cuál es la estructura de la tabla? ¿Tienes una clave de agrupamiento? –

Respuesta

10

Encontré la respuesta. Un pequeño error de un desarrollador de nuestro equipo (siempre culpo a todos los demás :-). Probablemente debería haber sabido la respuesta porque, una vez más, Martin Smith señaló en la otra pregunta que debería verificar ALLOW_ROW_LOCKS y ALLOW_PAGE_LOCKS. Pero en ese momento pensamos que partidid se relacionaba con una identificación de índice y solo revisé ese índice.

Lo que hice fue crear una nueva tabla con los mismos datos. El efecto se había ido y solo tenía el bloqueo IX correcto en la nueva mesa. Luego creé cada índice y probé entre cada creación hasta que repentinamente tuve el efecto otra vez.

yo encontramos este índice en OurTable:

CREATE NONCLUSTERED INDEX [IX_OurTable] ON [dbo].[OurTable] 
(
    [Col1] ASC, 
    [Col2] ASC, 
    [Col3] ASC, 
    [Col4] ASC, 
    [Col5] ASC 
) 
INCLUDE ([Col6], 
[Col7], 
[Col8], 
[Col9]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = OFF, ALLOW_PAGE_LOCKS = OFF, FILLFACTOR = 90) ON [PRIMARY] 
GO 

Con ALLOW_ROW_LOCKS = OFF y allow_page_locks = OFF es obvio que tendríamos este efecto en el inserto y también las selecciones.

Gracias por sus comentarios y muchas gracias a Martin que realmente me ayudó a resolver estos problemas de interbloqueo.

+1

Gracias por compartir su solución, parece una pregunta complicada y estoy seguro de que su publicación ayuda a otros. – jpierson

Cuestiones relacionadas