DataSet x DataReader : Uma questão de desempenho ?
Quem é que não gosta de fazer o menor esforço quando precisa codificar. Quanto se trata de acessar dados com VB .NET ou ASP .NET temos duas opções claras : DataSet e DataReader. E em se falando de pouco esforço quanto a codificação , com o DataSet podemos fazer o acesso basicamente com 3 linhas de código. Basta preencher o DataSet e a seguir fazer a interação usando um loop.
Mas e quanto ao desempenho ? Geralmente o desempenho é um requisito que vem em primeiro lugar , quer em aplicações Windows Forms quer em aplicações Web.
Quando se fala em desempenho a utilização de um DataReader leva vantagem sobre um DataSet. Com um DataReader você tem acesso aos dados assim que o objeto fica disponível e não necessita esperar , como no caso do DataSet , o seu preenchimento.
As vantagens do DataReader
A seguir temos um código que preenche um DataSet com o resultado de uma tabela e exibe o primeiro campo em cada linha:0
SqlConnection conn = new
SqlConnection(connectionString);
|
Dim conn As New SqlConnection(connectionString) |
C# |
VB.NET |
Observando o código você pode notar que a inspeção dos dados feita no loop foreach começa somente após o DataSet ter sido preenchido. Não dá para realizar outra tarefa enquanto o DataSet estiver sendo preenchido.
Vamos ver agora o código que realiza a mesma tarefa usando um DataReader:
SqlConnection
con = new SqlConnection(connectionString); |
Dim con As New SqlConnection(connectionString) Dim cmd As New SqlCommand("select * from tabela", con) cmd.Connection.Open() Dim dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) While dr.Read() Console.WriteLine(dr.GetString(0)) End While dr.Close() con.Close() |
C# | VB .NET |
Neste caso a inspeção dos dados é feita tão logo os dados estiverem disponíveis através de um loop While , onde dr.Read() retorna false se não encontrar dados. O DataReader armazena um resultado por vez no cliente , e , com isto reduz o uso de memória e recursos do sistema.
É óbvio que dependendo da situação somente um DataSet irá resolver a questão : serializar o resultado ou passar uma consulta para a próxima camada da sua aplicação , vai requerer uma coleção e um DataSet fornece um modelo adequado para estas tarefas.
Na maioria das consultas empregadas nas aplicações Web , onde os dados é pesquisado , exibido e então descartado um DataReader irá aumentar o desempenho da sua aplicação de forma significativa.
Então usar um DataReader é mais rápido que usar um DataSet . Certo ? Bem , sim e depende...
Será que não existe um modo de otimizar o desempenho de um DataSet para justificar sua utilização ?
Sim , existe e eu vou mostrar como você pode fazer isto. Antes vou mostrar o porque você quereria usar um DataSet.
Os DataSet possuem um conjunto de funcionalidades que os DataReaders não possuem , dentre eles destacamos:
Escolher usar um DataReader somente olhando a questão do desempenho irá fazer com que você não tenha acesso a estas funcionalidades.
Existem outros aspectos negativos em um DataReader que talvez o façam mudar de idéia. Em sistemas multiusuários , enquanto os DataSets/DataAdapters liberam suas conexões e bloqueios assim que o preenchimento via método Fill termina , os DataReaders estão gerenciando a conexão e qualquer bloqueio aberto durante todo o tempo que durar o loop de inspeção de dados. (dr.Read()). Isto pode levar a uma maior contenção do seu banco de dados e com isto diminuir o desempenho .
A única justificativa para usar um DataSet seria então melhorar seu desempenho.
Melhorando o desempenho de um DataAdapter
Você pode aproximar o desempenho de um DataAdapter de um DataReader desativando temporariamente algumas das funcionalidades avançadas padrão de um DataSet durante o processamento. Creio que os pontos chave em matéria de desempenho durante o processamento de um DataSet são a integridade referencial e a indexação que o DataSet usa para manter os dados internamente.
Abaixo temos um código que mostra o preenchimento de um Dataset , via DataAdapter , que possui duas tabelas do banco de dados Northwind.mdb : Customers e Employees
DataSet ds= new DataSet(); string strConn="Server=(local);dataBase=Northwind;user id=sa;password=;"; SqlConnection cn = new SqlConnection(strConn); string strSQL="select * from Customers;select * from employees"; cn.Open(); SqlDataAdapter da = new SqlDataAdapter( strSQL,cn); ds.Tables.Add("Customers"); ds.Tables.Add("Employees"); ds.EnforceConstraints =false; ds.Tables["Customers"].BeginLoadData(); da.Fill(ds.Tables["Customers"]); ds.Tables["Customers"].EndLoadData();
ds.Tables["Employees"].BeginLoadData(); |
Neste código tomamos algumas medidas para melhorar o desempenho do DataSet. Vejamos quais:
A primeira delas foi definir a propriedade - EnforceConstraints - como false ; isto desabilita a verificação das restrições durante a operação e pode tornar a operação mais rápida. Você pode voltar a definir o valor como True depois que os dados forem retornados dentro um loop try/Catch e tratando a exceção ConstraintException.
Outro fator que onera o desempenho de um DataSet é o estabelecimento de uma chave primária. Podemos também desabilitar temporariamente a indexação e notificação interna. Para isto fazemos o seguinte:
1- Executamos o método BeginLoadData
antes de usar o método Fill para desabilitar a
notificação , indexação.
2- Executamos o método EndLoadData depois de usar o método
Fill para habilitar a indexação a notificação.
Estes métodos são membros da classe DataTable e por isso você vai precisar chamá-los para a DataTable particular que você esta preenchendo.
Com isto melhoramos o desempenho do DataSet e com isto justificamos sua utilização afim de podermos usar seus recursos.
Aguarde mais artigos sobre ADO.NET...
José Carlos Macoratti