Muitas vezes começamos a escrever códigos e deixamos passar detalhes que podem afetar a performance do nosso sistema. Acreditamos que o problema de performance é maior do que realmente é e, consequentemente, acabamos seguindo caminhos mais complicados.
Vamos considerar algo simples. Você está usando o Dapper, um Micro ORM, que é conhecido por sua rapidez em relação a outros ORMs. Mas será que você está usando o Dapper corretamente e aproveitando ao máximo essa performance?
Você costuma identificar cuidadosamente os parâmetros que passa para suas consultas?
Vamos criar uma classe Cliente e uma tabela para armazenar os clientes:
class Cliente
{
public string Nome { get; set; }
public int Id { get; set; }
public string CPF { get; set; }
}
CREATE TABLE CLIENTE (
ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
NOME VARCHAR(200) NOT NULL,
CPF CHAR(11) NOT NULL
)
Depois de criar a tabela, vamos inserir 1000 CPFs (falsos) em um loop e criar um índice para CPF:
CREATE UNIQUE NONCLUSTERED INDEX IX_CLIENTE_CPF
ON Cliente (Cpf)
INCLUDE (Nome)
Agora, vamos escrever um código simples para obter um cliente através do CPF, que é um código comum em muitas aplicações:
IConfigurationBuilder builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false, true);
IConfigurationRoot config = builder.Build();
SqlConnection sqlConnection =
new SqlConnection(
config.GetConnectionString("ecommerceConnectionString")
);
sqlConnection.Open();
var cliente = sqlConnection.QueryFirstOrDefault<Cliente>(
"select * from Cliente where CPF = @cpf",
new { cpf = "00000000090" });
sqlConnection.Close();
O que esperamos é que a query executada no banco de dados seja a mais performática possível uma vez que temos um índice pela coluna CPF. Vamos provar que o índice existe e que estamos com o melhor plano de execução possível.
A query foi executada realizando um Index Seek no índice por CPF que criamos anteriormente.
Agora vamos executar pela aplicação a "mesma" query.
Executando a query direto no SQL e obtendo o plano de execução.
O resultado não foi o esperado. Ao invés de executar um Index Seek, a query gerada pelo Dapper realizou um Index Scan. Isso ocorreu porque o Dapper interpretou o parâmetro da consulta como NVARCHAR por padrão, o que fez com que o SQL Server convertesse o parâmetro e alterasse o plano de execução, afetando a performance da consulta.
Para evitar esse problema e melhorar a performance da consulta, é necessário informar o tipo do parâmetro de string corretamente. No Dapper, podemos usar a classe DbString para especificar o tipo de parâmetro.
var cliente = sqlConnection.QueryFirstOrDefault<Cliente>(
"select * from Cliente where CPF = @cpf",
new
{
cpf = new DbString
{
IsAnsi = true,
IsFixedLength = true,
Length = 11,
Value = "00000000090"
}
});
Ao definir as propriedades de DbString, o Dapper gera uma consulta com o tipo de parâmetro correto, permitindo que o SQL Server faça um Index Seek. Note que é importante especificar a propriedade corretamente, de acordo com o tipo de dado da coluna no banco de dados.
O DbString é uma classe do Dapper que permite especificar o tipo exato de um parâmetro que será passado para o banco de dados. Assim o Dapper gera uma instrução que utiliza o tipo de dado correto para o parâmetro. Com isso, evitamos conversões desnecessárias e ajudamos a melhorar a performance das consultas.
O construtor do DbString permite definir várias propriedades, como IsAnsi, IsFixedLength, Length e Value. A propriedade IsAnsi indica se o tipo de dado é ANSI ou Unicode. A propriedade IsFixedLength indica se o tipo de dado é de comprimento fixo ou variável. A propriedade Length indica o tamanho máximo do campo, e a propriedade Value é o valor do parâmetro.
Parâmetros de acordo com o tipo:
Esse pequeno detalhe muitas vezes passa despercebido durante as nossas implementações e pode afetar significativamente a performance de nossas aplicações, impactando diretamente na experiência dos usuários. Por isso, é importante dedicar tempo para otimizar o código, utilizando boas práticas e ferramentas que nos ajudem a identificar e corrigir possíveis problemas.
Até a próxima!
Top comments (2)
Show o artigo. Por acaso nao existe uma forma de configurar uma forma default? Porque isso facilitaria com menos codigo.
Fala meu camarada, obrigado por seu comentário. De fato, há uma outra forma de resolver esse problema. Você pode utilizar o seguinte trecho de código em C#:
No entanto, vale ressaltar que essa solução pode não ser ideal caso existam colunas no seu banco de dados definidas como NVARCHAR. É importante levar isso em consideração ao escolher a melhor abordagem para resolver o problema em questão.