Um cliente nosso está passando por impasses frequentes. Os impasses estão principalmente na mesma UPDATE
instrução. Os bloqueios seguem um padrão no qual ambos os SPIDs adquiriram um bloqueio de atualização (U) em uma página e ambos tentam converter o bloqueio de página U em um bloqueio de intenção exclusivo (IX). Às vezes, há apenas uma página envolvida; às vezes vários.
Capturamos um rastreamento de deadlock usando o sinalizador de rastreamento 1222 . O log do SQL Server mostra muitos, muitos impasses com o seguinte padrão (na ordem de baixo para cima):
waiter id=processe0dc2088 mode=U requestType=convert
waiter id=process2f9db2478 mode=U requestType=convert
waiter-list
owner id=processe0dc2088 mode=IX
owner id=process2f9db2478 mode=IX
owner-list
pagelock fileid=1 pageid=5794 dbid=2 objectname=tempdb.dbo.Item_Package_Site_Costs_Work id=lock1b22de480 mode=IX associatedObjectId=72057594131775488
resource-list
Ambos os processos estão executando a mesma instrução UPDATE para definir um sinalizador nesta tabela tempdb. Essa tabela tempdb contém informações que precisam persistir entre as chamadas do cliente até que o cliente termine. A tabela tem um índice bastante longo que começa com um GUID que representa um ID de processo exclusivo.
Estou tendo dificuldade de entender e simular esse impasse. Eu tentei várias quantidades de registros com dados simulados.
Minhas perguntas:
Por que esses processos estão adquirindo bloqueios U e depois convertendo para IX? Eu esperaria que o DELETE adquirisse bloqueios IX para começar.
Como evitar o impasse?
A instrução que causa o impasse está abaixo. O processo acabou de fazer uma pesquisa de custos para uma lista de itens em uma única loja. É tentar observar que houve um custo encontrado.
Observe que há um obsoleto (NOLOCK) em uma instrução UPDATE . Isso seria um fator contribuinte?
UPDATE tempdb..Item_Package_Site_Costs_Work
SET ItemPkgSiteCost_VINCostFound = 1,
ItemPkgSiteCost_VendCost_Key = SiteCosts_VendCost_Key
FROM tempdb..Item_Package_Site_Costs_Work (NOLOCK)
INNER JOIN #SiteCosts
ON ItemPkgSiteCost_GUID = @ProcGUID
AND SiteCosts_Item_Type = 0 -- Standard
AND ItemPkgSiteCost_Site_Key = SiteCosts_Input_Site_Key
AND ItemPkgSiteCost_Item_Key = SiteCosts_Item_Key
AND ItemPkgSiteCost_ItemPkg_Key = SiteCosts_Input_Sel_ItemPkg_Key
AND ItemPkgSiteCost_VendItem_Key = SiteCosts_VendItem_Key
AND ISNULL(ItemPkgSiteCost_Qty_Recv, 1) = SiteCosts_Input_Qty_Recv
A @@versão do servidor do cliente é:
Microsoft SQL Server 2005 - 9.00.4035.00 (X64) 24 de novembro de 2008 16:17:31 Copyright (c) 1988-2005 Microsoft Corporation Standard Edition (64 bits) no Windows NT 6.1 (Build 7601: Service Pack 1)
Até agora não consegui capturar o plano de consulta usado no momento do impasse, e as formas normais que tento recuperar o plano de consulta não estão retornando nada ( sys.dm_exec_query_plan e sys.dm_exec_text_query_plan ambos retornam NULL).
ATUALIZAÇÃO 2013-08-29
O cliente instalou o SQL Server 2005 SP 4, mas ainda está vendo esse impasse. Vou tentar remover o obsoleto (NOLOCK) nas tabelas que estão sendo modificadas e ver se isso corrige os impasses.
Em primeiro lugar, o processo está mantendo IX e deseja converter para U. Isso é esperado com a dica na consulta.
Ambas as consultas receberão o bloqueio IX durante a seleção e, em seguida, serão convertidas em U quando a alteração (se houver) precisar ocorrer.
Isso pode ser resolvido adicionando: WITH (XLOCK) como uma dica para a tabela temporária.