TroubleShooting - DEADLOCK, como acontecem!

/* Olá Senhores, Senhoras e Senhoritas DBAS!!!
 

      Existe um erro muito comum no SQL , mas que poucas pessoas entendem o que significa. Ele se chama DEADLOCK.
   
      Geralmente é assim que ele se apresenta

      Msg 1205, Level 13, State 45, Line 2

      Transaction (Process ID 194) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

      OU

      Msg 1205, Level 13, State 45, Line 2

      A transação (ID do processo 194) entrou em deadlock em bloquear recursos com outro processo e foi escolhida como a vítima do deadlock. Execute a transação novamente.

-- O que é o DEADLOCK?

      Basicamente significa que a transação A requisitou um recurso que está sendo utilizado pela Transação B e que a transação B está requisitando  um recurso trancado pela transação A. Ou seja, entramos em um Loop, onde A está esperando B concluir e B só conclui quando A terminar.

      Quando o SQL Server detecta essa situação ele mata o processo com rollback menos custoso ou pela transação mais velha.
      Mas nada melhor para entender do que um exemplinho.

*/


-- Abra uma query no seu Managment Studio e rode o seguinte código


use TabelasTemporarias


CREATE TABLE Tabela1 (Valor int)

CREATE TABLE Tabela2 (Valor int)


-- Agora vamos fazer a transação A. Iniciando uma transação e inserindo um valor -- na tabela 1. Não commite



BEGIN TRAN

INSERT INTO Tabela1 VALUES (0)

 

-- Abra uma nova query e crie a transação B, inserindo um valor na tabela 2.
-- Não comite.



BEGIN TRAN

INSERT INTO Tabela2 VALUES (0)


-- Volte para a primeira query e execute um SELECT na tabela 2


SELECT * FROM Tabela2

-- Você vai notar que a query vai ficar executando sem concluir, pois ela está 
-- esperando pelo primeiro processo. (vide query abaixo)

SELECT
      r.session_id [SessionID da Tran A],
      r.blocking_session_id [SessionID da Tran B],
      r.wait_type
FROM
      sys.dm_tran_locks l
inner join sys.dm_exec_requests r on l.request_session_id = r.session_id
WHERE
      request_status = 'WAIT'

/*
SessionID da Tran A SessionID da Tran B wait_type
------------------- ------------------- -----------------------------------------
194                 391           LCK_M_S

*/   


-- Ou seja, ja estamos no ponto onde A depende de B.
-- Por fim, vamos fazer B depender de A.
-- Na query da transação B, execute um select na Tabela 1.


SELECT * FROM Tabela1


-- E Voilá! Em poucos segundos você terá um erro matando a transação A.

  

/* O intuito aqui é só mostrar o que acontece, pois acredito que entender o problema é a melhor forma de resolve-la, para formas de reduzir o Deadlock e entende-lo profundamente seguem dois links oficiais






Se tiver duvidas, sugestões e reclamações me mande um email!


Abraços e Feliz Natal!!!

*/