Usuário com melhor resposta
Lentidão ao chamar dataReader.Close() utilizando CommandBehavior.SingleRow

Pergunta
-
Olá,Estou tendo o seguinte problema de performance ao utilizar o método Close() do IDataReader (DbDataReader, SqlDataReader, MySqlDataReader).O que estou tentando fazer é recuperar somente a primeira linha de qualquer consulta. No caso de uma consulta que retorna 100mil registros, eu consigo efetuar a leitura do primeiro registro rapidamente. Mas quando chamo o método dataReader.Close() ocorre uma lentidão inexplicável, coisa de 30seg. Métodos para recuperação de metaDados(GetSchema("Columns")) para esta mesma consulta também costumam ser lentas.Abaixo segue o código:
IDbConnection connection = new MySqlConnection(connectionString); IDbCommand command = connection.CreateCommand(); command.CommandText = "SELECT lavoura.* FROM lavoura, fazenda limit 100000" ; IDataReader reader; reader = command.ExecuteReader(CommandBehavior.SingleRow); // leitura do primeiro registro... reader.Close(); // aqui ocorre uma lentidão excessiva
Existe alguma outra forma de recuperar apenas a primeira linha de consultas que geram grande volume de dados, com uma boa performance? Gostaria de fazer isto somente utilizando os componentes do ADO.NET, não tendo a necessidade de incluir cláusulas nas consultas para limitar o resultado.No exemplo que passei, a consulta está sendo feita em um banco de dados MySql, mas este mesmo cenário irá se repetir em qualquer outro banco.Obrigado
Respostas
-
Tenta colocar a execução do DataReader dentro de um bloco using, chamando o cancel (obviamente dentro do bloco using), vê o que acontece. Não estou com o VS aqui para testar.
A sua pergunta sobre o ReadOnly eu não entendi, já que o DataReader por essência é somente leitura, certo?
Abraços
EDIT:
O código seria + ou - isso:
IDbConnection connection = new MySqlConnection(connectionString); IDbCommand command = connection.CreateCommand(); command.CommandText = "SELECT * FROM Tabela"; connection.Open(); IDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow); using (reader) { if (reader.Read()) { object o = reader[0]; } command.Cancel(); } connection.Close();
- Marcado como Resposta Marciel Ribeiro Ramos quarta-feira, 20 de janeiro de 2010 12:05
Todas as Respostas
-
-
Olá Murilo,Neste caso, o LIMIT foi imposto pelo cliente. Talvez o exemplo que eu passei não tenha sido o melhor. Em tabelas com 900mil registros por exemplo, tambem acontece o mesmo problema.SELECT * FROM TABELA1 , sendo que TABELA1 tem 900mil registros.Marciel
-
-
Murilo,Efetuei os seguintes testes:1) Troquei o reader.Close() por connection.Close() - Sem sucesso.2) Troquei a declaração das classes de acesso a dados que utilizavam as interfaces pelas classes do pacote MySql.Data.MySqlClient. - Sem sucesso.Tanto o close do connection como o do dataReader estão levando aprox. 30s.
-
Putz Marciel estou achando que tem a ver com a dll deles mesmo, porém não possuo experiência com essa quantidade imensa de dados, isso é, não sei se isso ocorre com o SqlConnection por exemplo, então não posso dar certeza. Desculpa por não poder ajudar.
-
-
-
Perguntinha besta: voce está fazendo a leitura do registro com um IF ao inves de While certo?
// leitura do primeiro registro
if (reader.Read())
{
}
2º e mais importante: se sua intencao é trazer um UNICO registro nesta consulta porque o Limit 100000 ? Por que não limitar a "1" como já dito mais acima? Essa é a coisa mais logica a ser feita.
Outro detalhe: qual é este unico registro? O primeiro incluido na tabela? O ultimo? Deve haver um criterio e, havendo, é so fazer o filtro WHERE......
Há um erro de conceito nisso ai.. do jeito que está, está "estranho".
[]s
Robson Castilho - MCTS .Net 2.0 Windows/Web Applications [Se o post foi útil, não esqueça de marcá-lo. Obrigado] -
Olá Robson,Estas consultas são feitas pelo usuário e podem ter origem em qualquer banco de dados (MySql, SQL Server, ODBC, etc...).No exemplo que passei, sugere que o usuário implantou este script em um banco MySQL usando LIMIT 100000, sendo isso fora do meu controle. Poderia ser qualquer consulta, usando ou não limit.Resumindo: estou com dificuldades de performance em descobrir qual a estrutura de colunas que uma consulta que resulta muitos registros (100mil ou mais) pode gerar, pois mesmo efetuando a leitura do primeiro registro (usando IF como voce mencionou), a chamada ao método Close() está muito lenta (coisa de 30s).ObrigadoMarciel
-
Amigão, o método Close passa por todos os registros de qualquer maneira, pois é assim que o DataReader funciona. Ele precisa disso para, por exemplo, atualizar a propriedade que diz quantos registro foram afetados. Por isso que fica lento desse jeito. Um workaround é chamar o método Cancel() do seu Command e depois o Close() do DataReader. Tenta aí e sinaliza se deu certo.
Abraços -
Olá Pedro,Obrigado pela explicação do método Close.Tentei utilizar o método Cancel. Só Mas não tive sucesso.
command.Cancel(); reader.Close();
Na chamada ao método reader.Close(), a aplicação disparou a seguinte excessão: Query execution was interruptedSobre esse processo que o Close faz qndo é invocado, isso também acontece quando eu efetuo uma consulta em modo ReadOnly? -
Tenta colocar a execução do DataReader dentro de um bloco using, chamando o cancel (obviamente dentro do bloco using), vê o que acontece. Não estou com o VS aqui para testar.
A sua pergunta sobre o ReadOnly eu não entendi, já que o DataReader por essência é somente leitura, certo?
Abraços
EDIT:
O código seria + ou - isso:
IDbConnection connection = new MySqlConnection(connectionString); IDbCommand command = connection.CreateCommand(); command.CommandText = "SELECT * FROM Tabela"; connection.Open(); IDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow); using (reader) { if (reader.Read()) { object o = reader[0]; } command.Cancel(); } connection.Close();
- Marcado como Resposta Marciel Ribeiro Ramos quarta-feira, 20 de janeiro de 2010 12:05
-
-
Trabalhei com a chamada do método Cancel em consultas utilizando ODBC e SQL Server e em ambas as situações o Cancel e o Close executaram sem problemas. No ODBC, utilizei uma consulta a um banco Oracle que retornava 49 milhoes de registros. Já no SQL Server, a consulta retornava 2 milhões.Me parece então que isto é um problema com o driver do MySql.Data. Mesmo utilizando a versão mais recente do site, o Close do dataReader, após o Cancel do command, gera a exceção Query execution was interrupted.Alguma sugestão?
-
Existe uma comunidade que dá manutenção nesse driver? Se sim, entre em contato como bug report, afinal, é um bug do provider. Ou ainda você perguntar por uma solução dentro do próprio fórum do MySql. Poste o link do seu post aqui, se vc chegar a criar, para que possamos acompanhar.
Abraços e boa sorte.
EDIT:
http://bugs.mysql.com/ -
Bom dia,Efetuei um post hoje no forum do MySql para verificar esta exceção que está ocorrendo.Vamos ver o que eles vão retornar.Obrigado mais uma vez.