Detectando e encerrando deadlocks
Um deadlock acontece quando duas ou mais tarefas bloqueiam uma à outra permanentemente, sendo que cada uma tem o bloqueio de um recurso que a outra tarefa está tentando bloquear. O seguinte gráfico apresenta uma exibição de alto nível de um estado de deadlock em que:
A tarefa T1 tem um bloqueio no recurso R1 (indicado pela seta de R1 para T1) e solicitou um bloqueio no recurso R2 (indicado pela seta de T1 para R2).
A tarefa T2 tem um bloqueio no recurso R2 (indicado pela seta de R2 a T2) e solicitou um bloqueio no recurso R1 (indicado pela seta de T2 a R1).
Como nenhuma tarefa pode continuar até que um recurso esteja disponível e nenhum recurso pode ser liberado até que uma tarefa continue, ocorre um estado de deadlock.
O Mecanismo de banco de dados do SQL Server detecta ciclos de deadlock automaticamente dentro do SQL Server. O Mecanismo de Banco de Dados escolhe uma das sessões como vítima de deadlock e a transação atual é encerrada com um erro para quebrar o deadlock.
Recursos que podem acarretar deadlock
Cada sessão de usuário pode ter uma ou mais tarefas sendo executadas em seu nome, sendo que cada tarefa pode adquirir ou aguardar para adquirir uma variedade de recursos. Os tipos de recursos a seguir podem causar bloqueio que pode resultar em um deadlock.
Bloqueios. A espera para adquirir bloqueios em recursos, como objetos, páginas, linhas, metadados e aplicativos pode causar deadlock. Por exemplo, a transação T1 tem um bloqueio compartilhado (S) na linha r1 e está esperando para obter um bloqueio exclusivo (X) em r2. A transação T2 tem um bloqueio compartilhado (S) na linha r1 e está esperando para obter um bloqueio exclusivo (X) em r1. Isso resulta em um ciclo de bloqueio no qual T1 e T2 esperam que uma libere os recursos bloqueados da outra.
Threads de trabalho Uma tarefa em fila aguardando um thread de trabalho pode causar um deadlock. Se a tarefa em fila possuir recursos que estão bloqueando todos os threads de trabalhado, haverá um deadlock. Por exemplo, a sessão S1 inicia uma transação e adquire um bloqueio compartilhado (S) na linha r1 e, depois, fica suspenso. As sessões ativas em execução em todos os threads de trabalhado disponíveis estão tentando adquirir bloqueios exclusivos (X) na linha r1. Como a sessão S1 não pode adquirir um thread de trabalho, ela não pode confirmar a transação e liberar o bloqueio na linha r1. Isso resulta em um deadlock.
Memória. Quando solicitações simultâneas estão esperando por concessões de memória que não podem ser satisfeitas com a memória disponível, pode ocorrer um deadlock. Por exemplo, duas consultas simultâneas, Q1 e Q2, são executadas como funções definidas pelo usuário que adquirem 10MB e 20MB de memória, respectivamente. Se cada consulta precisar de 30MB e a memória disponível total for de 20MB, Q1 e Q2 deverão esperar uma pela outra para liberar memória. Isso resulta em um deadlock.
Recursos relacionados à execução de consultas paralelas Threads de coordenação, produção ou consumo associados a uma porta de troca podem bloquear um ao outro causando um deadlock, normalmente ao incluir pelo menos um outro processo que não faz parte da consulta paralela. Além disso, quando uma consulta paralela começa a ser executada, o SQL Server determina o grau de paralelismo, ou o número de threads de trabalho, com base na carga de trabalho atual. Se a carga de trabalho do sistema for alterada inesperadamente, por exemplo, quando novas consultas forem executadas no servidor ou o sistema ficar sem threads de trabalho, poderá ocorrer um deadlock.
Recursos de vários conjuntos de resultados ativos (MARS). Esses recursos são usados para controlar a intercalação de várias solicitações ativas em MARS (consulte Ambiente de execução em lote e MARS).
Recurso do usuário. Quando um thread está esperando por um recurso que é potencialmente controlado por um aplicativo de usuário, o recurso é considerado como externo ou recurso de usuário e é tratado como um bloqueio.
Mutex de sessão. As tarefas que estão sendo executadas em uma sessão são intercaladas, ou seja, apenas uma tarefa pode ser executada na sessão em um determinado momento. Antes de a tarefa ser executada, deve ter acesso exclusivo ao mutex de sessão.
Mutex de transação. Todas as tarefas que estão sendo executadas em uma transação são intercaladas, ou seja, somente uma tarefa pode ser executada na transação em um determinado momento. Antes da tarefa ser executada, deve ter acesso exclusivo ao mutex de transação.
Para que uma tarefa seja executada em MARS, ela deve adquirir o mutex da sessão. Se a tarefa estiver sendo executada em uma transação, deverá adquirir o mutex de transação. Isso garante que apenas uma tarefa esteja ativa em um determinado momento, sessão e transação. Quando os mutexes solicitados forem adquiridos, a tarefa poderá ser executada. Quando a tarefa termina, ou está no meio da solicitação, primeiro ela libera o mutex de transação e, depois, o mutex de sessão em ordem reversa de aquisição. Porém, podem ocorrer deadlocks com esses recursos. No exemplo de código a seguir, duas tarefas, solicitação de usuário U1 e solicitação de usuário U2, estão sendo executadas na mesma sessão.
U1: Rs1=Command1.Execute("insert sometable EXEC usp_someproc"); U2: Rs2=Command2.Execute("select colA from sometable");
O procedimento armazenado que está sendo executado na solicitação U1 adquiriu o mutex de sessão. Se o procedimento armazenado levar muito tempo para ser executado, o Mecanismo de Banco de Dados presumirá que o procedimento armazenado está esperando uma entrada do usuário. A solicitação de usuário U2 está esperando pelo mutex de sessão, enquanto o usuário está esperando pelo conjunto de resultados de U2, e U1 está esperando por um recurso de usuário. Esse estado de deadlock é logicamente ilustrado como:
Detecção de deadlock
Todos os recursos listados na seção anterior participam do esquema de detecção de deadlock Mecanismo de Banco de Dados. A detecção de deadlock é executada por um thread de monitor de bloqueio que periodicamente inicia uma pesquisa por todas as tarefas em uma instância do Mecanismo de Banco de Dados. Os seguintes pontos descrevem o processo de pesquisa:
O intervalo padrão é de 5 segundos.
Se o thread de monitor de bloqueio localizar deadlocks, o intervalo de detecção de deadlock diminuirá de 5 segundos para até 100 milissegundos, dependendo da frequência de deadlocks.
Se o thread de monitor de bloqueio parar de localizar deadlocks, o Mecanismo de Banco de Dados aumentará os intervalos entre pesquisas para 5 segundos.
Se um deadlock tiver sido detectado há pouco tempo, presume-se que os próximos threads que precisarem esperar por um bloqueio estejam entrando no ciclo de deadlock. O primeiro par de esperas de bloqueio, após a detecção de um deadlock, dispara imediatamente uma pesquisa de deadlock em vez de aguardar pelo próximo intervalo de detecção de deadlock. Por exemplo, se o intervalo atual for de 5 segundos, e um deadlock tiver sido detectado há pouco tempo, a próxima espera de bloqueio iniciará o detector de deadlock imediatamente. Se essa espera de bloqueio fizer parte de um deadlock, será detectada imediatamente em vez de durante a próxima pesquisa de deadlock.
Normalmente, o Mecanismo de Banco de Dados executa somente a detecção periódica de deadlock. Como o número de deadlocks encontrado no sistema geralmente é pequeno, a detecção periódica de deadlock ajuda a reduzir a sobrecarga de detecção de deadlock no sistema.
Quando o monitor de bloqueio inicia a pesquisa de deadlock para um determinado thread, ele identifica o recurso em que o thread está esperando. O monitor de bloqueio localiza o proprietário desse recurso em particular e, recursivamente, continua a pesquisa de deadlock para esses threads até encontrar um ciclo. Um ciclo identificado dessa maneira forma um deadlock.
Depois que um deadlock é detectado, o Mecanismo de Banco de Dados encerra esse deadlock escolhendo um dos threads como uma vítima de deadlock. O Mecanismo de Banco de Dados encerra o lote atual que está sendo executado para o thread, reverte a transação da vítima de deadlock e retorna um erro 1205 para o aplicativo. A reversão da transação da vítima de deadlock libera todos os bloqueios mantidos pela transação. Isso permite que as transações dos outros threads sejam desbloqueadas e prossigam. O erro 1205 da vítima de deadlock registra informações sobre os threads e recursos envolvidos em um deadlock no log de erros.
Por padrão, o Mecanismo de Banco de Dados escolhe a sessão que está executando a transação mais fácil de ser revertida como a vítima de deadlock. Alternativamente, um usuário pode especificar a prioridade de sessões em uma situação de deadlock usando a instrução SET DEADLOCK_PRIORITY. O DEADLOCK_PRIORITY pode ser definida como LOW, NORMAL ou HIGH ou, alternativamente, pode ser definido como qualquer valor de inteiro no intervalo (-10 a 10). A prioridade de deadlock assume NORMAL como padrão. Se duas sessões tiverem prioridades de deadlock diferentes, a sessão com a prioridade mais baixa será escolhida como a vítima de deadlock. Se ambas as sessões tiverem a mesma prioridade de deadlock, a sessão com a transação menos dispendiosa para ser revertida será escolhida. Se as sessões envolvidas no ciclo de deadlock tiverem a mesma prioridade de deadlock e o mesmo custo, a vítima será escolhida aleatoriamente.
Ao trabalhar com CLR, o monitor de deadlock detecta automaticamente um deadlock para recursos de sincronização (monitores, bloqueio de leitura/gravação ou junção de thread) acessados dentro dos procedimentos gerenciados. Entretanto, o deadlock é resolvido ao se lançar uma exceção no procedimento selecionado como a vítima de deadlock. É importante entender que a exceção não libera automaticamente os recursos pertencentes à vítima; os recursos devem ser liberados explicitamente. Em consonância com o comportamento de exceção, a exceção usada para identificar uma vítima de deadlock pode ser capturada e ignorada.
Ferramentas de informações sobre deadlock
Para exibir informações sobre deadlock, o Mecanismo de Banco de Dados fornece ferramentas de monitoração na forma de dois sinalizadores de rastreamento e o evento gráfico de deadlock no SQL Server Profiler.
Sinalizadores de rastreamento 1204 e 1222
Quando acontecem deadlocks, os sinalizadores de rastreamento 1204 e 1222 retornam informações captadas no log de erros SQL Server 2005. O sinalizador de rastreamento 1204 relata informações de deadlock formatadas por cada nó envolvido no deadlock. O sinalizador de rastreamento 1222 formata informações de deadlock, primeiro por processos e depois por recursos. É possível permitir que ambos os sinalizadores de rastreamento obtenham duas representações do mesmo evento de deadlock.
Além de definir as propriedades dos sinalizadores de rastreamento 1204 e 1222, a tabela a seguir também mostra suas semelhanças e diferenças.
Propriedade |
Sinalizadores de rastreamento 1204 e 1222 |
Apenas sinalizador de rastreamento 1204 |
Apenas sinalizador de rastreamento 1222 |
---|---|---|---|
Formato de saída |
A saída captada no log de erros do SQL Server 2005. |
Focado nos nós envolvidos no deadlock. Cada nó tem uma seção dedicada e a seção final descreve a vítima de deadlock. |
Retorna informações em um formato parecido com XML que não está em conformidade com uma definição de esquema XML (XSD). O formato tem três seções principais. A primeira seção declara a vítima de deadlock. A segunda seção descreve cada processo envolvido no deadlock. A terceira seção descreve os recursos que são sinônimos com os nós no sinalizador de rastreamento 1204. |
Identificando atributos |
SPID:<x> ECID:<x>. Identifica o thread de ID de processo de sistema em casos de processos paralelos. A entrada SPID:<x> ECID:0, em que <x> é substituído pelo valor SPID, representa o thread principal. A entrada SPID:<x> ECID:<y>, em que <x> é substituído pelo valor SPID e <y> é maior que 0, representa os sub-threads para o mesmo SPID. BatchID (sbid para o sinalizador de rastreamento 1222). Identifica o lote do qual a execução de código está solicitando ou mantendo um bloqueio. Quando vários conjuntos de resultados ativos (MARS) estão desabilitados, o valor BatchID é 0. Quando MARS estão habilitados, o valor de lotes ativos é 1 para n. Se não houver lotes ativos na sessão, BatchID será 0. Mode. Especifica o tipo de bloqueio de um determinado recurso que é solicitado, concedido ou aguardado por um thread. O Mode pode ser IS (Tentativa Compartilhada), S (Compartilhado), U (Atualização), IX (Exclusivo da Tentativa), SIX (Exclusivo da Tentativa Compartilhado) e X (Exclusivo). Para obter mais informações, consulte Modos de bloqueio. Line # (line para o sinalizador de rastreamento 1222). Lista o número de linha no lote atual de instruções que estava sendo executado quando o deadlock aconteceu. Input Buf (inputbuf para o sinalizador de rastreamento 1222). Lista todas as instruções no lote atual. |
Node. Representa o número de entrada na cadeia de deadlock. Lists. O proprietário do bloqueio pode fazer parte destas listas:
Statement Type. Descreve o tipo de instrução DML (SELECT, INSERT, UPDATE ou DELETE) em que os threads têm permissões. Victim Resource Owner. Especifica o thread participante que o SQL Server escolhe como a vítima para quebrar o ciclo de deadlock. O thread escolhido e todos os sub-threads existentes são encerrados. Next Branch. Representa os dois ou mais sub-threads do mesmo SPID envolvidos no ciclo de deadlock. |
deadlock victim. Representa o endereço de memória físico da tarefa (consulte sys.dm_os_tasks (Transact-SQL)) selecionada como vítima de deadlock. Pode ser 0 (zero) no caso de um deadlock não resolvido. Uma tarefa que está sendo revertida não pode ser escolhida como vítima de deadlock. executionstack. Representa o código Transact-SQL que está sendo executado no momento em que o deadlock ocorre. priority. Representa a prioridade do deadlock. Em determinados casos, o Mecanismo de Banco de Dados pode optar por alterar a prioridade de deadlock para uma duração curta para obter uma simultaneidade melhor. logused. Espaço de log usado pela tarefa. owner id. A ID da transação que tem controle da solicitação. status O estado da tarefa. Pode ser um dos seguintes valores:
waitresource. O recurso requerido pela tarefa. waittime. O tempo em milissegundos de espera pelo recurso. schedulerid. O agendador associado à essa tarefa. Consulte sys.dm_os_schedulers (Transact-SQL). hostname. O nome da estação de trabalho. isolationlevel. O nível de isolamento da transação atual. Xactid. A ID da transação que tem controle da solicitação. currentdb. A ID do banco de dados. lastbatchstarted. A última vez em que um processo cliente iniciou uma execução em lote. lastbatchcompleted. A última vez em que um processo cliente concluiu uma execução em lote. clientoption1 e clientoption2. Defina as opções nessa conexão de cliente. Esse é um bitmask que inclui informações sobre opções normalmente controladas por instruções SET, como SET NOCOUNT e SET XACTABORT. associatedObjectId. Representa a ID de HoBT (heap ou árvore B). |
Atributos do recurso |
RID. Identifica a única linha dentro de uma tabela na qual um bloqueio é mantido ou solicitado. O RID é representado como RID: db_id:file_id:page_no:row_no. Por exemplo, RID: 6:1:20789:0. OBJECT. Identifica a tabela na qual um bloqueio é mantido ou solicitado. OBJECT é representado como OBJECT: db_id:object_id. Por exemplo, TAB: 6:2009058193. KEY. Identifica o intervalo de chave dentro de um índice em que um bloqueio é mantido ou solicitado. KEY é representado como KEY: db_id:hobt_id (index key hash value). Por exemplo, KEY: 6:72057594057457664 (350007a4d329). PAG. Identifica o recurso de página no qual um bloqueio é mantido ou solicitado. O PAG é representado como PAG: db_id:file_id:page_no. Por exemplo, PAG: 6:1:20789. EXT. Identifica a estrutura de extensão. EXT é representado como EXT: db_id:file_id:extent_no. Por exemplo, EXT: 6:1:9. DB. Identifica o bloqueio de banco de dados. DB é representado de um dos seguintes modos:
APP. Identifica o bloqueio feito por um recurso de aplicativo. APP é representado por APP: lock_resource. Por exemplo, APP: Formf370f478. METADATA. Representa os recursos de metadados envolvidos em um deadlock. Como METADATA tem muitos sub-recursos, o valor retornado depende do sub-recurso envolvido no deadlock. Por exemplo, METADATA.USER_TYPE retorna user_type_id =<integer_value>. Para obter mais informações sobre os recursos e sub-recursos de METADATA, consulte sys.dm_tran_locks (Transact-SQL). HOBT. Representa um heap ou árvore B envolvida em um deadlock. |
Nenhum exclusivo para esse sinalizador de rastreamento. |
Nenhum exclusivo para esse sinalizador de rastreamento. |
Exemplo do sinalizador de rastreamento 1204
O exemplo a seguir mostra a saída quando o sinalizador de rastreamento 1204 é ativado. Neste caso, a tabela em Node 1 é um heap sem índices, e a tabela em Node 2 é um heap com índices não clusterizados. A chave de índice em Node 2 é atualizada quando o deadlock ocorre.
Deadlock encountered .... Printing deadlock information
Wait-for graph
Node:1
RID: 6:1:20789:0 CleanCnt:3 Mode:X Flags: 0x2
Grant List 0:
Owner:0x0315D6A0 Mode: X
Flg:0x0 Ref:0 Life:02000000 SPID:55 ECID:0 XactLockInfo: 0x04D9E27C
SPID: 55 ECID: 0 Statement Type: UPDATE Line #: 6
Input Buf: Language Event:
BEGIN TRANSACTION
EXEC usp_p2
Requested By:
ResType:LockOwner Stype:'OR'Xdes:0x03A3DAD0
Mode: U SPID:54 BatchID:0 ECID:0 TaskProxy:(0x04976374) Value:0x315d200 Cost:(0/868)
Node:2
KEY: 6:72057594057457664 (350007a4d329) CleanCnt:2 Mode:X Flags: 0x0
Grant List 0:
Owner:0x0315D140 Mode: X
Flg:0x0 Ref:0 Life:02000000 SPID:54 ECID:0 XactLockInfo: 0x03A3DAF4
SPID: 54 ECID: 0 Statement Type: UPDATE Line #: 6
Input Buf: Language Event:
BEGIN TRANSACTION
EXEC usp_p1
Requested By:
ResType:LockOwner Stype:'OR'Xdes:0x04D9E258
Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)
Victim Resource Owner:
ResType:LockOwner Stype:'OR'Xdes:0x04D9E258
Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)
Exemplo do sinalizador de rastreamento 1222
O exemplo a seguir mostra a saída quando o sinalizador de rastreamento 1222 é ativado. Neste caso, uma tabela é um heap sem índices, e a outra tabela é um heap com um índice não clusterizado. Na segunda tabela, a chave de índice é atualizada quando o deadlock ocorre.
deadlock-list
deadlock victim=process689978
process-list
process id=process6891f8 taskpriority=0 logused=868
waitresource=RID: 6:1:20789:0 waittime=1359 ownerId=310444
transactionname=user_transaction
lasttranstarted=2005-09-05T11:22:42.733 XDES=0x3a3dad0
lockMode=U schedulerid=1 kpid=1952 status=suspended spid=54
sbid=0 ecid=0 priority=0 transcount=2
lastbatchstarted=2005-09-05T11:22:42.733
lastbatchcompleted=2005-09-05T11:22:42.733
clientapp=Microsoft SQL Server Management Studio - Query
hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user
isolationlevel=read committed (2) xactid=310444 currentdb=6
lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
executionStack
frame procname=AdventureWorks2008R2.dbo.usp_p1 line=6 stmtstart=202
sqlhandle=0x0300060013e6446b027cbb00c69600000100000000000000
UPDATE T2 SET COL1 = 3 WHERE COL1 = 1;
frame procname=adhoc line=3 stmtstart=44
sqlhandle=0x01000600856aa70f503b8104000000000000000000000000
EXEC usp_p1
inputbuf
BEGIN TRANSACTION
EXEC usp_p1
process id=process689978 taskpriority=0 logused=380
waitresource=KEY: 6:72057594057457664 (350007a4d329)
waittime=5015 ownerId=310462 transactionname=user_transaction
lasttranstarted=2005-09-05T11:22:44.077 XDES=0x4d9e258 lockMode=U
schedulerid=1 kpid=3024 status=suspended spid=55 sbid=0 ecid=0
priority=0 transcount=2 lastbatchstarted=2005-09-05T11:22:44.077
lastbatchcompleted=2005-09-05T11:22:44.077
clientapp=Microsoft SQL Server Management Studio - Query
hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user
isolationlevel=read committed (2) xactid=310462 currentdb=6
lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
executionStack
frame procname=AdventureWorks2008R2.dbo.usp_p2 line=6 stmtstart=200
sqlhandle=0x030006004c0a396c027cbb00c69600000100000000000000
UPDATE T1 SET COL1 = 4 WHERE COL1 = 1;
frame procname=adhoc line=3 stmtstart=44
sqlhandle=0x01000600d688e709b85f8904000000000000000000000000
EXEC usp_p2
inputbuf
BEGIN TRANSACTION
EXEC usp_p2
resource-list
ridlock fileid=1 pageid=20789 dbid=6 objectname=AdventureWorks2008R2.dbo.T2
id=lock3136940 mode=X associatedObjectId=72057594057392128
owner-list
owner id=process689978 mode=X
waiter-list
waiter id=process6891f8 mode=U requestType=wait
keylock hobtid=72057594057457664 dbid=6 objectname=AdventureWorks2008R2.dbo.T1
indexname=nci_T1_COL1 id=lock3136fc0 mode=X
associatedObjectId=72057594057457664
owner-list
owner id=process6891f8 mode=X
waiter-list
waiter id=process689978 mode=U requestType=wait
Evento gráfico de deadlock de designer de perfil
Este é um evento do SQL Server Profiler que apresenta uma representação gráfica das tarefas e recursos envolvidos em um deadlock. O exemplo a seguir mostra a saída do SQL Server Profiler quando o evento de gráfico de deadlock é ativado.
Para obter mais informações sobre a execução do gráfico de deadlock do SQL Server Profiler, consulte Analisando deadlocks com o SQL Server Profiler.