Conversão Implícita – Vilão Silencioso

DBA e Consultor de Banco de Dados

Conversão Implícita – Vilão Silencioso

Tempo de leitura: 4 minutos

Fala Galera,

Espero que estejam todos bem!

Hoje vou falar sobre um problema que já enfrentei diversas vezes ao longo da minha carreira. As famosas conversões implícitas de tipo no SQL Server. Esse é daqueles problemas que passam despercebidos no desenvolvimento mas que podem causar uma dor de cabeça gigantesca em produção.

Recentemente estava analisando uma query que estava rodando lenta em um cliente e descobri que o problema era justamente isso. Vou compartilhar com vocês o que aprendi sobre esse assunto.

Um caso real que me aconteceu

Certa vez, peguei um chamado para analisar onde uma procedure que sempre rodou bem de repente começou a dar timeout para o cliente. A primeira coisa que fiz foi olhar o plano de execução e notei algo estranho: ao invés de um Index Seek eficiente, estava acontecendo um Index Scan na tabela inteira.

Depois de investigar, descobri que alguém havia alterado um parâmetro de entrada da procedure de VARCHAR para NVARCHAR (Não me pergunte o porque, estou até hoje tentando entender porque fizeram isso 🙃). Apesar de parecer uma mudança inocente, causou um estrago enorme na performance da procedure do cliente.

O que são essas conversões de Tipo?

Vamos entender melhor o que acontece por baixo dos panos.

O SQL Server trabalha com diversos tipos de dados: NÚMEROS INTEIROS (INT), DECIMAIS (DECIMAL), STRINGS (CHAR,VARCHAR,NVARCHAR..), DATAS (DATE,DATETIME), BINÁRIOS (BIT) e por aí vai. Cada um desses tipos tem suas particularidades e formas específicas de armazenamento.
Quando você escreve uma query que compara ou combina dados de tipos diferentes, o SQL Server precisa “igualar” esses tipos para conseguir fazer a operação. É como se ele dissesse: “Cara, você está tentando somar maçã com banana, vou ter que converter uma das duas para a mesma fruta”.

Por exemplo, se você tentar somar o número 5 com a string ‘3’, o SQL Server vai converter a string ‘3’ para o número 3 e o resultado será 8.

 

Quando o SQL Server faz essas conversões sozinho?

Aqui está o ponto importante.  Quando você não especifica explicitamente como quer que essa conversão seja feita, o SQL Server faz isso automaticamente para você. Isso é chamado de conversão implícita.

Na maioria das vezes isso funciona bem e nos ajuda a escrever código mais simples. Mas em alguns casos pode causar problemas sérios de performance.

Um exemplo prático para entendermos melhor

Vou mostrar um exemplo usando uma tabela de funcionários. Imaginem que temos uma coluna CodigoFuncionario definida como VARCHAR(10).

Primeiro cenário – sem conversão implícita:

Neste caso, tanto a variável quanto a coluna são VARCHAR(10). O SQL Server consegue usar o índice normalmente e faz um Index Seek eficiente.

Segundo cenário – com conversão implícita:

Agora mudei a variável para NVARCHAR(10). Aparentemente uma mudança pequena, mas que causa um impacto gigantesco.

O que acontece nos bastidores?

Quando temos tipos diferentes sendo comparados, o SQL Server precisa decidir qual dos dois vai ser convertido. Existe uma hierarquia de precedência que determina isso.

No nosso exemplo, o NVARCHAR tem precedência maior que o VARCHAR. Então o SQL Server vai converter a coluna CodigoFuncionario de VARCHAR para NVARCHAR antes de fazer a comparação.

É como se a query se tornasse isso:

O Problema de performance

Aqui está o grande problema. Quando você aplica uma função (incluindo CONVERT) em uma coluna no WHERE, o SQL Server não consegue mais usar o índice de forma eficiente.

Ao invés de ir direto na linha que precisa (Index Seek), ele precisa ler toda a tabela ou todo o índice (Index Scan) aplicando a conversão em cada linha para depois fazer a comparação.

Em uma tabela pequena isso pode passar despercebido. Mas em uma tabela com milhões de registros, isso vira um pesadelo.

Como Identificar essas conversões?

O plano de execução é seu melhor amigo para identificar essas conversões. Quando você tem uma conversão implícita, aparece um aviso amarelo no operador que está sendo afetado.
Se você usar o SQL Server Management Studio ou no finado Azure Data Studio, vai ver uma mensagem parecida com esta:
“”Type conversion is expression (CONVERT_IMPLICIT …) may affect “” in query plan choice””

Essa mensagem é um sinal vermelho de que você tem um problema de conversão implícita.

 

 

Como resolver o problema?

A solução mais simples é garantir que os tipos sejam compatíveis. No nosso exemplo, seria:


Opção 1 – Mudar o tipo da variável:

Opção 2 – Mudar o tipo da coluna:

Opção 3 – Fazer a conversão explícita na variável:

A terceira opção força a conversão da variável ao invés da coluna, mantendo o índice utilizável.

Dicas Importantes para o dia a dia

  • Sempre declare suas variáveis com o mesmo tipo das colunas que você vai comparar;
  • Tenha cuidado especial com VARCHAR VS NVARCHAR – essa é uma pegadinha muito comum (Principalmente em ORMs : Entity Framework, Hibernate .. etc, as vezes é só questão de parametrizar corretamente na aplicação para evitar cair nessas armadilhas);
  • Fique atento aos tipos de dados quando usar parâmetros em procedures e functions;
  • Sempre analise os planos de execução procurando por avisos de conversão implícita;
  • Se você precisar fazer conversões, prefira converter a variável/parâmetro ao invés da coluna;

Conclusão

As conversões implícitas são um daqueles detalhes que podem passar despercebidos mas que fazem uma diferença gigantesca na performance. É importante estar atento a isso principalmente quando estamos trabalhando com tabelas grandes.
Uma simples mudança de tipo de dados pode transformar uma query que roda em milissegundos numa query que demora minutos para executar.

Sempre que estiverem analisando problemas de performance, não se esqueçam de verificar se existem conversões implícitas acontecendo. Muitas vezes esse é o culpado pela lentidão.

É isso pessoal! Espero que essa dica possa ajudar vocês a evitarem dores de cabeça com performance no SQL Server.

Se já passaram por situações similares ou têm outras dicas sobre performance, compartilhem nos comentários! A troca de experiências sempre nos ajuda a crescer.

Um grande abraço a todos, até a próxima!

Gustavo Larocca

Consultor SQL Server

 

Deixe uma resposta

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.