Desenvolvimento - ADO.NET

Aumentando a perfomance no LinqToSql

Sempre que penso em LinqToSql, penso em como seria a performance em uma aplicação de grande porte, por isso, estudei algumas dicas que podem ajudar a melhorar a performance.

por Alexandre Minato



Titulo: Aumentando a perfomance no LinqToSql.

Uma das dúvidas que sempre tive é como uma aplicação de grande porte baseada no LinqToSql se comportaria. Hoje trabalho em um segmento (bolsa de valores) onde performance é extremamente necessário. Sabemos que tabelas com grande concorrência sem a utilização do NOLOCK pode apresentar grandes problemas, este problema ainda não sei como resolver, mas uma coisa que consegui é estudar algumas soluções que podem melhorar a performance no LinqToSql.

A primeira coisa foi criar uma tabela com tamanho razoável (Estou utilizando uma tabela de uma aplicação real) para tentar espelhar uma realidade (com tipos Nullables, campos preenchidos, não preenchidos e etc). A tabela contém mais de um milhão de registros (1.015.232) com 16 campos.

Select com a quantidade de registros (1.015.232) mais de um milhão registros

Tipo de dados e campos da tabela

É importante entender quando podemos desativar as propriedades ObjectTrackingEnabled e DeferredLoadingEnabled.

Entidade criada a partir do LinqToSql (dbml)

ObjectTrackingEnabled = Essa propriedade só deve ser desativada quando for uma operação de SELECT, ou seja, qualquer outra ação que manipule informações no banco de dados (INSERT, UPDATE ou DELETE), deve ter a propriedade habilitada, caso contrário, você irá se deparar com a seguinte exception.

Object tracking is not enabled for the current data context instance.

Exception disparada pela falta do ObjectTracking

Quando existe um relacionamento no banco de dados e você cria o ORMcom o LinqToSql são criadas relações entre as tabelas e você pode ter acesso a tabela relacionadas, por exemplo, se na tabela cliente houvesse uma tabela relacionada com tipo de cliente, poderíamos ter acesso ao tipo desta forma

ClienteEntidade.TipoClienteEntidade.TipoCliente

Ocorre que pode se tornar um problema quando há uma grande quantidade de registros, por uma boa prática devemos desabilitar este objeto e habilitarmos apenas quando necessário. Uma alternativa para carregar apenas a tabela necessária (quando há mais de duas tabelas relacionadas) é utilizar LoadWith .

Para desabilitar o mapeamento de entidades relacionadas é desabilitar a propriedade DeferredLoadingEnabled.

Agora vamos ver na prática se isso funciona mesmo. Vamos aos testes.

Como sou desconfiado de resultados baseado em uma única execução, eu sempre acho que fica algo em cache, que fica algo na memória, enfim, fiz algumas repetições para garantir.

class Program

{

    static void Main(string[] args)

    {

        Stopwatch timer = new Stopwatch();

        int qtde = 0, qtdadeTracking = 0;

        for (int i = 0; i < 3; i++)

        {

            Console.WriteLine("Iteração: " + i);

            timer.Start();

            using (dbDadosDataContext db = new dbDadosDataContext())

            {

                qtde = db.ClientesEntidades.ToList().Count;

            }

            timer.Stop();

            Console.WriteLine("Tempo com as propriedades habilitadas {0} qtade {1:N0}", timer.Elapsed, qtde);

            timer.Reset();

            timer.Start();

            using (dbDadosDataContext db = new dbDadosDataContext())

            {

               

                db.DeferredLoadingEnabled = false; // Desabilitando as tabelas relacionadas.

                db.ObjectTrackingEnabled = false; // Desabilito o tracking

                qtdadeTracking = db.ClientesEntidades.ToList().Count;

            }

            timer.Stop();

            Console.WriteLine("Tempo com as propriedades desabilitadas {0} - qtdade {1:N0}", timer.Elapsed, qtdadeTracking);

        }

        Console.ReadKey();

    }

}

Resultado do teste: É possível diminuir pela metade o tempo de execução.

Espero que tenham gostado. Sigam no Twitter @DicaDoNerd. – www.alexandreminato.com.br

Alexandre Minato

Alexandre Minato - Analista de Sistemas, atualmente trabalha em uma grande instituição financeira (Itaú-Unibanco), na área de mercado de renda variável (www.itautrade.com.br), com experiência de 7 anos na área de TI, inicialmente com VBA, VB, ASP clássico e há 3 anos com a platataforma .NET. (C# + ASP.NET).
Moderador de uma das maiores comunidades de Office System do Brasil (http://comunidade.itlab.com.br) e Participante em Fóruns da MSDN.
Website: www.alexandreminato.com.br