LINQ - Pré-compilando consultas para ganhar desempenho
Se o termo LINQ é novo para você recomendo que acesse a seção do site onde vai encontrar diversos artigos apresentando e usando a tecnologia LINQ.
Hoje vou falar sobre um recurso que você pode usar para melhorar o desempenho das suas consultas LINQ: A pré-compilação.
Este artigo baseia-se em uma tradução literal do artigo - Pre-compiling Queries for Performance (Doug Rothaus);
Sabe aquelas consultas complexas que você usa repetidas vezes ? Elas são as candidatas preferidas a utilização desse recurso.
Na pré-compilação de uma consulta LINQ é feito um processamento para compilar a consulta um única vez e na próxima execução ela já estará compilada e pronta para ser executada.
Para criar consultas pré-compiladas você usa o método Compile da classe CompiledQuery do namespace System.Data.Linq.
Na prática você passa uma expressão lambada que contém as variáveis usadas pela consulta, o objeto DataContext, as variáveis , etc. para o método Compile para criar a consulta compilada. Veja abaixo um exemplo :
Dim query As Func(Of NorthwindDataContext, Customer, IQueryable(Of Order)) = _ System.Data.Linq.CompiledQuery.Compile( _ Function(database As NorthwindDataContext, cust As Customer) _ From order In database.Orders _ Where order.Customer Is cust) |
Na primeira vez que a consulta for executada, ela será compilada e armazenada em uma variável especificada. Depois disso, a consulta compilada será usada quando a consulta for executada novamente.
Vamos dar um exemplo básico com LINQ usando este recurso criando uma aplicação Windows Forms que acessa o banco de dados Northwind.mdf e exibe uma relação de clientes do banco de dados Northwind usando uma consulta LINQ e uma lista de detalhes de seus pedidos para o cliente selecionado usando uma consulta LINQ pré-compilada.
Vamos ao trabalho...
Abra o Visual Basic 2008 Express Edition e crie uma aplicação Windows Forms a partir do menu Arquivo->Novo Projeto;
Opa ! O meu VB 2008 Express esta em português !!! Quer traduzir o seu ??? Se quiser baixe o pacote de tradução no sítio:
Veja a aparência do projeto no VB 2008 Express traduzido:
A seguir uma dica do colega: Thiago Nogueira Matuchaki para traduzir o VS 2008:
Eu consegui colocar o VS2008 Professional Edition em português (não testei se funciona no Team System, mas provavelmente sim). O que eu fiz instalei o SQL Server 2008 Express Editon (Em português). http://www.microsoft.com/express/sql/download/ Depois instale o VS2008, automaticamente o VS2008 ficou em português. Mas caso não queira que fique em português mais basta ir no menu -> Ferramenta -> opções, Em Ambiente -> Configurações internacionais e na parte direita escolha o idioma desejada English ou Português. |
A seguir a partir do menu Projeto->Adicionar Novo Item e na janela Modelos selecione LINQ to SQL Classes, altere o nome para Northwind.dbml e clique em Adicionar;
O Descritor Objeto relacional LINQ será exibido vazio. Vamos então definir o mapeamento O/RM usando LINQ.
Visualize a janela Gerenciador de banco de dados e localize a conexão com o banco de dados Northwind.mdf . (se você não tem uma conexão criada com o Northwind.mdf você deverá criá-la.)
Expanda os objetos do banco de dados e arraste a tabela Customers e Orders para o Descritor OR/M LINQ;
Selecione o formulário na janela Gerenciador de Soluções e inclua os componentes:
Monte o leiaute do formulário conforme a figura abaixo:
Vamos agora código necessário para exibir os dados:
Declarando o import usado no projeto:
Imports
System.Data.LinqDefinindo as variáveis , a expressão lambda e instanciando um objeto StopWatch
'definindo a expressÆo lambda Private consultaPedido As Func(Of NorthwindDataContext, Customer, IQueryable(Of Order)) ' O objeto
DataContext do LINQ to SQL para o Northwind. ' Define as vari veis que vÆo
medir o tempo para exibir a diferen‡a de desempenho |
Nota:
A interface
IQueryable
fornece a funcionalidade para avaliar consultas em uma fonte de dados
específica no qual o tipo de dados é conhecido. A interface IQueryable<(Of <(T>)>) se destina a implementação por provedores de consulta. Essa interface herda a interface IEnumerable<(Of <(T>)>) de forma que se ela representa uma consulta , o resultado da consulta pode ser enumerado. Consultas que não retornam resultados enumeráveis são executadas quando o método Execute<(Of <(TResult>)>)(Expression) é chamado. |
Agora vamos definir o método getPedidos() que irá retornar os pedidos de um cliente usando uma consulta pré-compilada:
Private Function getPedidos(ByVal selectedCustomer As Customer) As List(Of Order)' Compila a consulta para pedidos se ela nÆo foi compilada ainda. ' Caso contr rio usa a consulta compiladaIf consultaPedido Is Nothing Then
Function(database As NorthwindDataContext, clientes As Customer) _ From pedidos In database.Orders _ Where pedidos.Customer Is clientes)
End
If
|
No evento Load do formulário vamos definir o seguinte código que vai preencher o ListBox com os dados da tabela Clientes;
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load' Obtem a lista de clientes e vincula no ListBox1. ListBox1.DataSource = From clientes In db.Customers _ Select clientes _ Order By clientes.CompanyName
ListBox1.DisplayMember =
"CompanyName" |
Agora devemos implementar o código a seguir no evento SelectedIndexChanged do ListBox de forma que quando um cliente for selecionado os seus pedidos sejam buscados e exibidos. Além disso iremos calcular o tempo gasto nesta operação e exibir no controle Label;
Ao selecionar um cliente o evento irá passar o cliente atual selecionado para o método gePedidos() para chamar a consulta pré-compiada e retornar os pedidos do cliente.
Os tempos exibidos referem-se ao tempo atual gasto para executar a consulta pré-compilada e o tempo gasto na primeira execução quando a consulta não estava pré-compilada.
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
tempoConsulta.Start() ' Se um cliente foi selecionado , obtem a lista de pedidos para o cliente ' e vincula no DataGridView1. If ListBox1.SelectedValue IsNot Nothing Then DataGridView1.DataSource = getPedidos(ListBox1.SelectedValue) End IftempoConsulta.Stop() tempoAtual = tempoConsulta.ElapsedMilliseconds If tempoLento Is Nothing OrElse tempoAtual > tempoLento Then tempoLento = tempoAtual End IfLabel1.Text = "Tempo gasto atual : " & tempoAtual & " # tempo primeira execu‡Æo: " & tempoLentoEnd Sub |
Nota:
O objeto Stopwatch
é muito útil para calcular o tempo que foi gasto entre dois intervalos de
tempo em uma aplicação VB .NET.
Para usar o objeto Stopwatch
você precisa chamar o seu método Start para iniciar a contagem do
tempo; o método Stop interrompe a contagem. O método Reset é
útil para limpar a contagem do tempo iniciando o contador. |
Executando o projeto iremos obter:
Observe que o tempo gasto na consulta pré-compilada é bem menor que na primeira execução.
Pegue o projeto completo aqui : LinqConsultasCompiladas.zip
Eu sei é apenas LINQ mas eu gosto...
Referências:
José Carlos Macoratti