Apaixonado por tecnologia. Trabalho com tecnologia desde 2003.

Saiba mais sobre minha vida profissional aqui .

Fale comigo.
Siga-me no Twitter
Ultimos comentários
Calendário de Posts
<<  novembro 2017  >>
stqqssd
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

Siga o @DicaDoNerd no Twitter e acompanhe as novidades


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 cois 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
Entidade criada a partir do LinqToSql (dbml)

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

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 ORM com o LinqToSql são criadas relações entre as tableas e você pode ter acesso a tabela relacionadas, por exemplo, se na tabela cliente houvesse uma tabela relacionada com tipo de cliente, porderí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 unica 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.

É comum precisarmos saber quais foram valores alterados, para que as alterações sejam logadas. Há um método GetModifiedMembers() no LinqToSql.  publiquei um artigo que mostra como podemos criar um XML (XElement) com as informações alteradas, com um pouco de criatividade é possível unir as duas funciondalidades.

Espero que gostem.

Até a próxima!

Minato 8-)

Tem alguma sugestão para vídeo aula, artigo? Entre em contato

Estou trabalhando em um projeto pessoal em parceria com um amigo para fazer o portal administrativo do site www.baladacerta.com.br, surgiu a necessidade de criarmos log de alterações do usuário. A idéia era logarmos as alterações dos clientes em um campo do tipo XML do SQLServer 2005.

Como estou desenvolvendo com LinqToSql e com conceitos de OO, pensei em como poderia fazer a geração do Log dinamicamente. Vai aí uma dica para quem gosta de soluções automatizadas.

Para garantir que as entidades que serão comparadas são do mesmo tipo, garanto no WHERE do próprio método (where T : Y), utilizando Reflection para gerar os elementos e atributos do XML (XElement)

Ficou bem dinâmico e reutilizável.

public enum Modulo
{
Casas,
CasasDetalhes,
Financeiro,
Parceiros,
}


public XElement GravarAlteracoes<T , Y >( T EntidadeAnterior, Y NovaEntidade, Modulo modulo ) where T : Y
{

XElement xml = new XElement(modulo.ToString()); // Crio o elemente referente ao módulo

//Pego as propriedades de uma das entidades (já que as duas são iguais).
PropertyInfo [] propriedades = EntidadeAnterior.GetType().GetProperties();
//Variável que armazena o valor das propriedades
object valorAntigo, valorNovo;

//passo por todas as propriedades da entidade
foreach (PropertyInfo propriedade in propriedades)
{
//Atribuo valor as entidades.
valorAntigo = propriedade.GetValue(EntidadeAnterior, null);
valorNovo = propriedade.GetValue(NovaEntidade, null);

//Se for Null, gravo o Literal NULL
valorAntigo = valorAntigo == null ? "NULL" : valorAntigo;
valorNovo = valorNovo == null ? "NULL" : valorNovo;

//Verifico se os valores são diferentes
if (!valorAntigo.Equals(valorNovo))
{
xml.Add(new XElement(propriedade.Name, // Crio um elemento com o nome da propriedade
new XAttribute("ValorAnterior", valorAntigo), // um atributo com o valor antigo
new XAttribute("ValorAtual", valorNovo))); // um atributo com o novo valor.
}

}

return xml;
}

Para utilizar você poderia fazer assim:

XElement xml = Log.GravarAlteracoes<CasaEntidade, CasaEntidade>(entCasaBanco, entCasaTela, Log.Modulo.Casas);

O interessante é que conseguimos garantir que as duas entidades são do mesmo tipo.

Simples não é mesmo?

 

Minato.

 
teste