Estou tentando entender um impasse. A tabela em questão mytb
é usada apenas na seguinte consulta:
delete mytb with (uplock,holdlock) where key_value=@value
chamado por meio de sp_executesql. Ambos os processos mencionados posteriormente usam o mesmo código, exceto o valor da chave.
Estou usando o sinalizador de rastreamento 1222, aqui está a parte da lista de recursos do log do servidor:
resource-list
objectlock lockPartition=0 objid=1433553235 subresource=FULL dbid=16 objectname=mydb.dbo.mytb id=lock5620a3480 mode=IX associatedObjectId=1433553235
owner-list
owner id=process4bd94c8 mode=IX
waiter-list
waiter id=process4c85288 mode=X requestType=convert
objectlock lockPartition=0 objid=1433553235 subresource=FULL dbid=16 objectname=mydb.dbo.mytb id=lock5620a3480 mode=IX associatedObjectId=1433553235
owner-list
owner id=process4c85288 mode=IX
waiter-list
waiter id=process4bd94c8 mode=X requestType=convert
Meu entendimento é o seguinte: Ambos os processos (vamos chamá-los de "c8" e "88" de seus dois últimos caracteres de id) conseguiram obter o mesmo bloqueio IX na tabela, que depois tentam se transformar em um bloqueio X para excluir o necessário linha, mas um processo bloqueia o outro.
Meu entendimento está correto? Se sim, por que os processos estão compartilhando o bloqueio IX? O sistema não deveria negar acesso a um bloqueio IX para o processo que o condiciona a corrida mais lento, o que faria com que o primeiro processo fosse concluído primeiro, então o segundo poderia começar?
Adição de comentário de postagem: Ao pesquisar mais, descobri que um índice na where
condição não existe, enquanto eu esperava que fosse a chave primária clusterizada. A ausência desse índice poderia ser a causa do impasse?
Sim. Cada consulta começará com um bloqueio IX e, em seguida, começará a adquirir bloqueios U em intervalos de teclas. Ele usará o bloqueio de intervalo por causa da
holdlock
dica, caso contrário, seriam bloqueios U regulares nas teclas individuais.mas depois de varrer vários milhares de linhas com (updlock,holdlock), cada uma tentará escalar o bloqueio para um bloqueio X no nível da tabela (os bloqueios de objetos são particionados)
Nenhuma sessão pode obter um bloqueio X na tabela, pois a outra possui um bloqueio IX incompatível, portanto, um impasse.
Com um índice seletivo, cada sessão precisaria apenas ler e bloquear um punhado de valores de chave e, portanto, não seria escalado para um bloqueio de tabela.