Mostrando postagens com marcador Deadlock. Mostrar todas as postagens
Mostrando postagens com marcador Deadlock. Mostrar todas as postagens

sexta-feira, 24 de junho de 2016

FUN! Deadlock art generator

Contexto: Estou ministrando um treinamento in-company e preparando uma série de novas demonstrações para este cliente. Após escrever uma procedure que era para ser problemática, esbarrei em deadlocks mais interessantes do que eu havia planejado….

Gostei da brincadeira e resolvei compartilhar com vocês um deadlock art generator!

Algumas imagens da saída estão abaixo. Também coloquei no OneDrive um trace com alguns deadlocks que eu coletei.





A primeira ver que ouvi falar sobre deadlock art foi em um post do Catae (https://blogs.msdn.microsoft.com/fcatae/2010/03/18/deadlock-art/) que sempre cito no módulo de locking nos meus treinamentos.

Para reproduzir em seu ambiente, você vai fazer o seguinte.

    1. Crie a procedure proc_Divertida no AdventureWorks2014
    2. Utilizando o SQLQueryStress, mande 20/30 threads com 3/4 execuções “EXEC proc_Divertida;”
        a. O número de threads/repetições você muda de acordo com seu interesse na arte. kkkk
    3. Monitore o deadlock graph no profiler

HAVE FUN!

Abraços,


USE AdventureWorks2014
GO
IF OBJECT_ID('dbo.proc_Divertida') IS NOT NULL
     DROP PROCEDURE dbo.proc_Divertida
go
CREATE PROCEDURE dbo.proc_Divertida
AS 

     DECLARE @OrderID INT = (CAST((RAND() * 100000) AS INT) % 30000) + 43659;
     PRINT @OrderID

     BEGIN TRANSACTION

           UPDATE Sales.SalesOrderDetail
                SET UnitPrice = UnitPrice
           WHERE SalesOrderID = @OrderID

           ; WITH C AS (
                SELECT (Quantity * ActualCost) AS LineTotal, PRODUCTID, TransactionDate
                FROM Production.TransactionHistory
                UNION
                SELECT (Quantity * ActualCost), PRODUCTID, TransactionDate
                FROM Production.TransactionHistoryArchive
                UNION
                SELECT (UnitPrice * OrderQty), SOD.ProductID, SOH.OrderDate 
                FROM Sales.SalesOrderDetail AS SOD
                INNER JOIN Sales.SalesOrderHeader AS SOH
                ON SOH.SalesOrderID = SOD.SalesOrderID
           )
           SELECT 
                C.ProductID,
                YEAR(TransactionDate),
                SUM(LineTotal)  
           FROM C
           GROUP BY GROUPING SETS (ProductID, YEAR(TransactionDate), (ProductID, YEAR(TransactionDate)), ())

     COMMIT TRANSACTION
GO

Luciano Caixeta Moreira - {Luti}
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm
www.srnimbus.com.br

segunda-feira, 20 de setembro de 2010

Sim, é um deadlock

Se você prefere ler o artigo em PDF, baixe aqui.


Revisando os posts da última semana eu encontrei um post interessante do nosso amigo Alexandre Lopes, que mostra um exemplo bem legal de deadlock. O post na íntegra está aqui: http://sqlserverday.com.br/alopes/?p=924 e aconselho lê-lo antes de continuar com
este post. Leu tudo? Então vamos a uma análise mais detalhada.


Monitorando com o profiler os eventos lock:acquired e lock:released, execute no banco de dados AdventureWorks a consulta “SELECT * FROM Sales.CurrencyRate” e veremos (Figura 01) que o lock manager optou por pegar um bloqueio de página, então temos um IS no objeto e, durante a leitura dos registros, o SQL Server vai pegando e liberando os bloqueios compartilhados na medida em que os registros das páginas são lidos.
clip_image002
(Figura 01)

Agora vamos ao deadlock, com base no script abaixo:

(Script 01)

USE AdventureWorks
go

select @@TRANCOUNT

-- Conexão 01
BEGIN TRAN

UPDATE Sales.CurrencyRate SET AverageRate = 2 WHERE CurrencyRateID =1
SELECT * FROM Sales.CurrencyRate

-- Script 02
BEGIN TRAN

UPDATE Sales.CurrencyRate SET AverageRate = 2 WHERE CurrencyRateID = 1

Quando iniciamos a transação da conexão 01 e executamos o primeiro update, veremos o SQL Server pegando um lock exclusivo no registro e IX na página e tabela (Figura 02).

clip_image004
(Figura 02)

Se a partir de outra conexão executarmos o mesmo comando de update, o que é de se esperar? Que o SQL Server requisite os mesmos recursos e a transação fique bloqueada pelo registro exclusivo colocado sobre a chave. Vejamos a saída do SP_LOCK para análise na figura 03.

clip_image006
(Figura 03)

Vemos claramente que a conexão de SPID 55 ficou bloqueada (WAIT) esperando que a conexão 52 libere o bloqueio exclusivo sobre o registro que está sendo atualizado. Outro ponto que eu quero chamar a atenção é para o bloqueio IX da página 1040, que foi concedido para a transação de SPID 55.

Se buscarmos no BOL o tópico “Lock Compatibility” veremos que IX são compatíveis com IX e até existe uma nota sobre isso: “An intent exclusive (IX) lock is compatible with an IX lock mode because IX means the intention is to update only some of the rows rather than all of them. Other transactions that attempt to read or update some of the rows are also permitted as long as they are not the same rows being updated by other transactions”.


Porém se analisarmos a tabela de compatibilidade, veremos que o bloqueio compartilhado (S) não é compatível com o IX, pois eu não poderia ler uma página em que algum registro estivesse sendo alterado, seria uma leitura suja não compatível com o nível de isolamento read committed. Acho que vocês já devem ter percebido onde eu quero chegar...


Se nesse momento nós voltarmos para a primeira transação que está com o bloqueio exclusivo no registro e executarmos o SELECT para buscar todos os registros, o que veremos? Sim senhor, um deadlock. E os recursos envolvidos são detalhados na figura 04.

clip_image008
(Figura 04)

Analisando a saída acima, vemos as sessões 52 e 55 se bloqueando, então estamos em uma situação de deadlock, onde o SQL Server deve escolher uma vítima. Os recursos envolvidos são o registro bloqueado pelo lock exclusivo e a página 1040, onde a transação do SPID 52 fica bloqueada com o status CNVT (Convert). Pela documentação do SQL Server: “CNVRT: The lock is being converted from another mode, but the conversion is blocked by another process holding a lock with a conflicting mode”.

Então o deadlock aconteceu porque estamos trabalhando em níveis de granularidade diferentes, um na página e outro no registro! Se o que eu acabei de afirmar for verdade, esse tipo de deadlock pode ser resolvido com uma hint no SELECT, onde indicamos que o SQL Server deve pegar bloqueios de registros, e não de página: “SELECT * FROM Sales.CurrencyRate (ROWLOCK)”. Faça o teste e verá que realmente dessa forma o deadlock não irá acontecer.

Conclusão

O comportamento do SQL Server está correto e é realmente um deadlock, então vou discordar do Alexandre em relação à qualidade do produto e que não existe um deadlock, mas sim tentar pensar como um program manager do produto. Qual é o maior ganho para o SQL Server? Permitir bloqueios de registro e utilizar o IX para indicar que existe algum recurso com menor granularidade sendo bloqueado (acelerando a análise de compatibilidade dos bloqueios) ou evitar esse comportamento impedindo bloqueios de registro ou análises custosas de compatibilidade de bloqueios em diferentes níveis (imagine bilhões de registros, um bloqueio exclusivo em um registro e outra transação pedindo um bloqueio compartilhado na tabela). Eu também ficaria com o row lock.

No fim eu gostei bastante de fazer essa pequena análise, pois é um excelente exemplo (e não muito comum) de um deadlock que o Alexandre trouxe para nós, possibilitando mostrar para vocês um pouco mais do SQL Server e seu funcionamento.


Abraços e até um próximo artigo.

[]s
Luciano Caixeta Moreira - {Luti}
luciano.moreira@srnimbus.com.br www.twitter.com/luticm www.srnimbus.com.br

terça-feira, 1 de dezembro de 2009

Trigger causando deadlock

Ontem recebi uma ligação de um profissional de TI precisando de uma ajuda com o SQL Server relativo a um problema de deadlock. Mesmo com o dia cheio, aproveitei que era feriado e Brasília, e resolvi ajudar o camarada. Depois compenso o tempo perdido de madrugada...

Respondendo a ele eu acabei me empolgando e escrevi um documento explicando o que estava acontecendo, qual o resultado da resolução do deadlock que foi proposta e qual o impacto em termos de desempenho da solução que eles trabalham.

O artigo pode ser encontrado no meu skydrive.



Depois eu vou parar e formatar o artigo como um post, mas não será agora pois estou com pressa.

[]s
Luciano Caixeta Moreira - {Luti}
Chief Innovation Officer
Sr. Nimbus Serviços em Tecnologia Ltda
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm