Dicas do dia a dia – Melhorando a performance reduzindo os waits do T-Log

Olá pessoal tudo certo?

No post de hoje quero compartilhar com vocês uma situação que é bastante comum no meu dia a dia de Consultor de Banco de Dados SQL Server.

Estava realizando uma atividade de tuning em um cliente e percebi que quando executava algo que escrevia no log de transação e acompanhava o progresso através da sp_whoisactive ( http://whoisactive.com/ ) eu visualizava alguns WAITs relacionados ao log de transação.

Antes de simular o problema, vamos entender de maneira rápida e simples como funciona o Transaction Log no SQL Server.

Como sabemos, quando estamos executando algum comando que faça a alteração, inserção ou exclusão de dados, o SQL Server primeiro grava a operação no Transaction Log para depois escrever no disco, correto?

R: NÃO!!!

Nesse meio aí tem um outro camarada chamado Log Buffer, que é uma região em memória que está dentro do buffer pool do SQL Server. Somente após o checkpoint que vai acontecer um flush dos dados que estão em memória e eles serão movidos para o disco.

Agora vamos simular o problema.

Para simular o problema eu vou criar uma nova database na minha instância chamada “Wait_Log” e armazenei o Transanction Log em um HD externo. Após criar a database, criei uma tabela e depois vou fazer umas inserções através do QueryStress.

CREATE TABLE TBL_PAGAMENTO
(ID_Pessoa INT,
Dt_Pagamento DATETIME,
Vl_Pagamento DECIMAL,
)

Ao executar a seguinte query em 10 threads no QueryStress, comecei a ter os seguintes WAITs.

DECLARE @id INT
SET @id = 1
   WHILE @id < 10000
   BEGIN
	INSERT INTO TBL_PAGAMENTO
       	VALUES
           (@id,
		   DATEADD(MINUTE,+75,GETDATE())
           ,53.232+0.05)
	SET @id = @id + 1
   END

Com o cenário criado, encontramos dois WAITs diferentes relacionados ao Transaction Log: “WRITELOG” e “LATCH-EX [LOG_MANAGER]”.

WRITELOG – De maneira simples, esse é o WAIT mais comum relacionado ao T-Log. Ele está relacionado ao tempo que a Engine do SQL Server está esperando para escrever no T-Log.

LATCH-EX [LOG_MANAGER] – Esse WAIT é comum quando o SQL Server está realizando o auto-growth do arquivo do T-Log. Repare que no print acima as transações com esse WAIT estão sendo bloqueadas pela transação com o ID 74, justamente a transação que está fazendo o arquivo do T-Log crescer.

Também podemos ver o valor alto de “Log Flush Waits” no perfmon, além do nosso valor de batch request estar baixo.

Como podemos tentar resolver ou amenizar esse problema?

Bom, a primeira opção seria fazer uma optimização no código, tentando quebrar o código em intervalos menores, ou então uma opção que testei foi a dica que o Fabiano Amorim deu no seu treinamento, 25 Dicas de Performance, na plataforma de treinamentos do #TeamFabricioLima, que é colocar o WHILE dentro de uma transação.

DECLARE @id INT
SET @id = 1
begin tran
   WHILE @id < 10000
   BEGIN
    INSERT INTO TBL_PAGAMENTO
           VALUES
           (@id,
           DATEADD(MINUTE,+75,GETDATE())
           ,53.232+0.05)
    SET @id = @id + 1
   END
 commit

Vamos comparar a performance.Os WAITs reduziram drasticamente, praticamente não consegui capturar mais o WRITELOG.

Vamos comparar a performance.

Os WAITs reduziram drasticamente, praticamente não consegui capturar mais o WRITELOG.

As estatísticas do consumo também melhoraram bastante!

Como podemos observar, o contator “Log Flush Wait Time” ficou zerado, o contador “Log Flushes/sec” também reduziu bastante!

E tempo de execução tivemos alguma melhora?

R: SIM!!!

O tempo de execução baixou de mais de 2 minutos para 45 segundos! Ou seja, foi reduzido mais da metade do tempo!

Por que tivemos essa melhora?

Essa melhora ocorreu por que o SQL Server processou as 10 mil inserções em uma única transação. Nem sempre é possível realizar essa otimização, mas ela pode ser uma boa solução. Já imaginou todo o trabalho que o SQL Server tem para abrir e fechar 10 mil transações? Agora imagine como seria muito mais simples fazer tudo em uma única transação!

Podemos realizar outras melhorias?

R: SIM!!!

Podemos utilizar uma funcionalidade do SQL Server chamada Delayed Durability. Quando habilitamos essa funcionalidade o SQL Server passa a “ignorar” o log de transação e escreve direto no disco.

Se você quiser conhecer mais sobre essa funcionalidade, o Caio Amante tem um vídeo no seu blog (O funcionamento do Delayed Durability) que demonstra como utilizar, os benefícios e os riscos.

--- O VALOR DEFAULT É DISABLED
ALTER DATABASE Wait_Log SET DELAYED_DURABILITY = FORCED

Vamos executar a query novamente e verificar se vamos ter alguma melhora no tempo e nos contadores.

DECLARE @id INT
SET @id = 1
begin tran
   WHILE @id < 10000
   BEGIN
    INSERT INTO TBL_PAGAMENTO
           VALUES
           (@id,
           DATEADD(MINUTE,+75,GETDATE())
           ,53.232+0.05)
    SET @id = @id + 1
   END
 commit

Vamos as comparações.

Os contadores tiveram uma melhora considerável.

O “Log Flush Wait Time” ficou zerado e quase triplicou os “Batch Requests”.

Novamente não consegui capturar o WAIT WRITELOG.

Além disso, o tempo de execução da nossa query caiu de 45 para 20 segundos!

Como podemos ver, os benefícios de habilitar o “Delayed Durability” são grandes, ainda mais se for uma base ou instância de BI e ETL, onde uma perda mínima de dados e tolerável.

Poxa Tiago, legal até aí, mas tem mais alguma coisa que podemos melhorar?

R: SIM!!!

Até aqui conseguimos obter grandes melhorias sem realizar investimentos financeiros (“R$$$$$$$”), mas agora o patrão liberou uma verba e vamos torrar essa grana em um hardware TOP. Em ambientes OLTP, normalmente devemos privilegiar o arquivo de log em um disco rápido, então se você tem condições de mover o seu transaction log para um disco mais rápido, ou SSD, você vai melhorar ainda mais a performance da nossa query.

Para finalizar, vou fazer um último teste. Agora o meu arquivo de T-Log também está armazenado em um disco SSD. Os contadores de performance tiveram alguns ganhos.

O “Log Flush Wait Time” ficou zerado e chegamos a quase 14 mil “Batch Requests/Sec”!

Novamente não tivemos o WAIT WRITELOG.

Além do tempo de execução ter baixado de 20 para 13 segundos.

Além disso, existem outras boas práticas que podemos utilizar para melhorar ainda mais a performance do T-Log, como por exemplo na hora de criar a database, alterar o auto-growth do T-Log para crescer em “MB” e não em “%”. Além disso, se você puder estimar o tamanho do T-Log e já criá-lo no tamanho ideal, você evita operações de growth no T-Log e consequentemente o WAIT LATCH-EX [LOG_MANAGER] (vide o print do início do post).

Além dessas dicas, sempre tomem cuidado com a fragmentação dos VLFs (Virtual Log File), eles podem impactar na performance das suas queries, no tempo do restore dos seus backups e o tempo de sua instância voltar no caso de algum crash.

Se você quiser saber mais sobre os cuidados com a fragmentação do T-Log, segue uma série de posts que recomendo a leitura.

Controle Automático dos VLFs – Edvaldo Castro

Fragmentação do Transaction Log – Parte 1 – Leandro Ribeiro

Fragmentação do Transaction Log – Parte 2 – Leandro Ribeiro

Transaction Log VLFs – too many or too few? – Kimberly L. Tripp

Se você quiser fazer um curso sinistro e o melhor de tudo de forma gratuita, tem um treinamento de T-Log Internals do Luti no Youtube.

https://www.youtube.com/playlist?list=PLGaWZx_3bztdZNnrFSluDpaPjaB6IAx6-

Bom pessoal por hoje é isso.

Um grande abraço.

Tiago Neves

Curta a minha página no facebook e fique por dentro das novidades do mundo SQL Server.

Deixe uma resposta