Fala pessoal! Tudo bem com vocês? Animados para mais um post???
Introduction
Hoje eu quero bater um papo com vocês sobre algo que pode ser uma verdadeira “pegadinha” para quem está migrando do SQL Server On-premises (ou até do Azure SQL Database) para o Azure SQL Managed Instance (MI) e que eu aprendi na prática.
Sabe aquela rotina clássica de DBA de olhar para um arquivo de log que cresceu demais depois de uma manutenção pesada e pensar: “Vou rodar um Shrink aqui para liberar esse espaço não utilizado”? Pois é, no Managed Instance, especificamente no tier General Purpose – Standard, essa “boa prática” pode se tornar o seu pior pesadelo de performance.
O Cenário: O hábito do Shrink
No mundo On-premises, manter arquivos de dados e log com o tamanho “justo” é quase um mantra para economizar storage e manter a organização.
No meu caso, estava trabalhando em ambiente muito grande, vi um arquivo de log que estava com 900 GB de espaço alocado e menos de 1 GB utilizado. Ainda mais se tratando de arquivo de log, é natural que qualquer DBA SQL Server imediatamente pense em rodar um shrink para recuperar esse espaço alocado, certo? Aà que mora o problema quando o banco em questão está em um Azure SQL Managed Instance no tier Standard.
No Azure SQL Managed Instance, se você estiver utilizando os tiers mais novos como o Next-gen General Purpose ou o Business Critical, você tem uma flexibilidade maior e o problema que vou detalhar nesse post não acontece. Mas a grande maioria dos ambientes ainda roda no General Purpose (Standard), e é aqui que o bicho pega.
Diferente de um disco local onde o IOPS costuma ser fixo pelo tipo do disco, no Managed Instance Standard, a performance de I/O (IOPS e Throughput) é diretamente proporcional ao tamanho que você aloca para o arquivo.
Isso significa que o Azure reserva performance para você baseado no tamanho do arquivo, seja o arquivo de dados (mdf) ou arquivo de logs (ldf). Se você tem um arquivo de log de 1 TB, você tem um limite 7500 IOPS. Se você roda um shrink e esse arquivo cai para 100 GB, você acabou de reduzir os IOPS do disco para 500, reduzindo a performance do seu disco (e do banco) em 15x, muitas vezes sem perceber.
De acordo com a documentação oficial da Microsoft, o escalonamento funciona em faixas.
Faixas de tamanho e IOPS do arquivo:

O Problema Real: O “Efeito Dominó”
Imagine que você rodou o shrink no log às 21h numa rotina de manutenção. O arquivo foi de 600 GB para 50 GB. Às 08h, vários jobs demorando muito mais pra executar, a aplicação com lentidão e todo mundo reclamando com você. Como o log agora só tem 500 IOPS (em vez de 5.000), cada INSERT, UPDATE ou DELETE demora 10x mais para confirmar o commit no disco.
O resultado? Wait types de LOG_RATE_GOVERNOR ou WRITELOG lá no alto, aplicação lenta, usuários reclamando e você olhando para o CPU e vendo que está tudo baixo. Aà você pensa: “Mas eu não mudei nada, só limpei o log!” rs.
E agora, o que fazer?
A recomendação aqui muda um pouco o mindset do DBA tradicional:
- Evite Shrink: Se o seu arquivo de log cresceu para 200 GB e você sabe que, periodicamente, ele precisa desse espaço para manutenções ou cargas, deixe ele lá. O custo do storage extra é muito menor do que o custo do downtime ou da lentidão da aplicação.
- Monitore as faixas de IOPS: Você até pode rodar o Shrink, mas tenha cuidado para não mudar as faixas de performance de IOPS e se essa redução da velocidade do disco não irá trazer impactos. Antes de reduzir um arquivo, verifique na documentação se você não vai cair para uma “faixa de performance” inferior.
- Avalie o Next-gen GP: Se performance de disco é um gargalo constante e você precisa de flexibilidade, considere migrar para o tier Next-gen General Purpose, onde o IOPS é isolado do tamanho do arquivo (você pode pagar pelo IOPS que desejar).
Para ajudar vocês a identificar qual a faixa de velocidade de cada arquivo do seu ambiente, preparei um script simples para ajudar vocês no dia a dia:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
SELECT DB_NAME(database_id) AS [Database Name], [name] AS [Logical Name], [type_desc] AS [File Type], CAST(size * 8.0 / 1024 / 1024 AS DECIMAL(10, 2)) AS [Size (GiB)], -- Lógica baseada nos tiers oficiais de IOPS CASE WHEN (size * 8.0 / 1024 / 1024) <= 129 THEN 500 WHEN (size * 8.0 / 1024 / 1024) <= 513 THEN 2300 WHEN (size * 8.0 / 1024 / 1024) <= 1025 THEN 5000 ELSE 7500 END AS [Official IOPS], -- Lógica baseada nos tiers oficiais de Throughput (MiB/s) CASE WHEN (size * 8.0 / 1024 / 1024) <= 129 THEN 100 WHEN (size * 8.0 / 1024 / 1024) <= 513 THEN 150 WHEN (size * 8.0 / 1024 / 1024) <= 1025 THEN 200 ELSE 250 END AS [Official Throughput (MiB/s)], physical_name AS [Physical Path] FROM sys.master_files WHERE database_id > 4 ORDER BY [Size (GiB)] DESC; |
Conclusão
Se você está sentindo que o seu WRITELOG está alto, dê uma olhada no tamanho do seu arquivo de log. Se ele estiver com 100 GB, você está limitado a 500 IOPS. Se você aumentar esse arquivo para 514 GB (mesmo que não use todo esse espaço), o Azure vai te liberar 5.000 IOPS na hora!
Vale lembrar que isso se aplica ao tamanho do arquivo de dados também, não é apenas para o arquivo de log não.
Às vezes, “desperdiçar” um pouco de storage é o melhor investimento que você pode fazer na performance do seu banco de dados no Azure.
Espero que tenham gostado dessa atualização, um grande abraço e até a próxima!
