Fast Lane Reader

Olá…
Estou com graves problemas com o desempenho de um sistema swing com banco postgre…
Ao coletar dados do banco são criados objetos para cada registro no banco e então jogados numa List…
Ex:

...
List objetos = new ArrayList();
ResultSet rs = ppst.executeQuery();
while (rs.next()) {
    Objeto obj = new Objeto();
    obj.setAtributo1(rs.getString(1));
    obj.setAtributo2(rs.getDouble(2));
    objetos.add(obj);
}

então… essa List é retornada e na hora de eu listar numa JTable (por exemplo), itero cada objeto e listo um por um…
ex:

for (Iterator it = objetos.iterator; it.hasNext;) {
     Objeto obj = (Objeto)it.next;
     System.out.println(obj.getAtributo1()+" - "+obj.getAtributo2());
}

só que deste jeito, se tenho 500 registros no banco, a demora para realizar um select e trazer os objetos vai de 10 a 15 MINUTOS!
como faço pra resolver esse problema sendo q o postgres suporta 9223372036854775807 registros numa tabela e nao chego nem ao 600???
ouvi falar num design pattern Fast Lane Reader mas de acordo com o que li ele destrói com a programação em camadas…
O que faço pra resolver esse problema??
não acredito que terei que violar a POO para agilizar esse processo…
claro que eu não esperava ter 50000 registros no banco e buscálos em 1 segundo… mas 500 registros passar de 15 MINUTOS?? isso eu nunca imaginei…
espero a ajuda de alguém…
obrigado…

Como diria o velho filósofo: Tem caroço nesse angú(nunca comi um angú, então não sei oq isso significa)
Cara, por mais camadas e camadas desnecessárias que o seu software tenha, ele não pode ser tão não performático.
Cara, faz uns profilers. Acho que o jProfiler pode te ajudar nisso. Primeiro, tente isso, depois volte aqui e nos diga o que exatamente o jProfiler te disse.

o jProfiler é um monitor de performance…
não tem uma solução pra isso sem eu precisar ficar testando a performance que eu sei que é péssima?
agradeço a ajuda…

Comece pelo simples, o que está demorado?
A consulta? O populate da JTable?

o que demora é colocar objeto por objeto na memória e depois iterar e listar na JTable…
o select em si é rápido…
se eu der esse select no psql, por exemplo… não chega a dar 1 segundo e consigo listar pouco mais de 1000 registros…
o que demora mesmo é a criação de cada objeto (cada registro na tabela é um objeto que será listado individualmente na JTable)

Configurações da máquina:
Windows Vista Ultimate
2GB memória
proc Athlon X2
160 GB HD

essa demora é normal??
obs.: com até 100 registros no banco a performance é muito boa… agora… se passar de 500 fica INVIÁVEL mexer no sistema…
obrigado…

Use um profiler para medir onde está o problema de performance e corrija-o.

600 registros é um número muito pequeno. Com certeza existe um erro crasso em algum lugar, e vc não está vendo.

farei isso…
mas o problema na performance não estaria na hora de criar objeto por objeto vindo do ResultSet e depois listá-los individualmente??
problema de banco não é, acredito que de máquina também não…
farei o que vocês recomendaram e depois posto aqui…
obrigado…

Realmente, só pra te dar uma ideia, tenho uma telinha aqui com um JTable e carreguei 15000 registros.
Tudo isso, ou seja, consulta, criação de objetos no hibernate, serializar tudo e passar na rede, pegar do outro lado
da rede, criar os objetos e popular a JTable levou em torno de 18 segundos.

Baseado em coisas que já fiz que eram parecidas com esta eu diria que o tempo total não deveria passar de 2 segundos.

Me diz uma coisa, este código:

... List objetos = new ArrayList(); ResultSet rs = ppst.executeQuery(); while (rs.next()) { Objeto obj = new Objeto(); obj.setAtributo1(rs.getString(1)); obj.setAtributo2(rs.getDouble(2)); objetos.add(obj); }

Espelha a sua realidade?

Quero dizer, você cria um objeto aplica apenas 2 sets, é isto?

Minha dica é detectar inicialmente o ponto exato onde está consumindo maior tempo (como já disseram antes) depois a gente pensa em uma solução.

P.S O banco de dados as vezes apresenta o resultado rapidamente para nós por causa de uma coisa chama fetch que normalmente é de 10 ou 15 linhas (isto é configuravel e diferente entre bancos) se não me engano, portanto fica esperto com a marcação de tempo no loop que lê o resultset.

flws

to configurando um plugin profiler no eclipse…

não… na verdade tenho um resultSet com 23 colunas…
obs.: não utilizo hibernate

Postarei o relatório do profiler em html…

Esse é o html gerado do Eclipse TPTP…
Fiz um outro teste e notei o seguinte:
500 registros retornados do banco demoram aproximadamente 30 segundos;
1000 registros do banco passam de meia hora (tempo máximo que eu esperei e provavelmente os registros não seriam retornados)…
“teoricamente” 1000 registros teriam que demorar 1 minuto (levando em contaos 500 registros)
outra: esse tempo informado pelo relatório é meio duvidoso (ao meu ver)…
agradeço a ajuda de todos…

O profiler indica os seguintes métodos, onde é gasto 80% do tempo do seu código:
JFEmail.getBg_carros()
JFEmail.initComponents()

Verifique se vc não está construindo a tela várias vezes, por acidente. O método initComponents não deveria estar sendo chamado tantas vezes, nem estar consumindo tanto tempo.

Também vale a pena você pedir para seu profiler inspecionar pelo menos 1 nível das classes do Java. Não sei exatamente onde faz isso no TPTP. Mas, do jeito que você tirou, acabamos vendo só os seus métodos de negócio e tendo pouca idéia de que parte deles, exatamente, gera o problema.

pro isso que eu disse q esse diagnóstico é duvidoso…
os números não batem com a realidade…
como o meu initComponents ta ocupando 80% e quando há poucos registros no banco ele só ocupa 34%???
detalhe: o initConponents SÓ cria a tela (não chama nada do banco) e os métodos como listClientes e listVeiculos (que trazem dados do banco) são chamados no constructor da classe…
poderiam me recomendar um profiler (de preferência free) que realmente faça um teste correto?
e outra: como o tempo de execução das classes do pacote database (ou seja, as classes referentes à conexão e as DAOs) é praticamente nulo se o tempo da execução varia de acordo com a quantidades de registros no banco??

Use o profiler do Netbeans. Eu sempre achei ele anos luz à frente do TPTP.

Antes de rodar a consulta, zere os dados do profiler (o do Netbeans permite isso). O que pode estar acontecendo é que ele está totalizando por thread. E o initComponent ocupou muito tempo da thread de pintura. E claro, saber disso não serve para você.

[quote=erico_kl]Olá…
Estou com graves problemas com o desempenho de um sistema swing com banco postgre…
Ao coletar dados do banco são criados objetos para cada registro no banco e então jogados numa List…
Ex:

...
List objetos = new ArrayList();
ResultSet rs = ppst.executeQuery();
while (rs.next()) {
    Objeto obj = new Objeto();
    obj.setAtributo1(rs.getString(1));
    obj.setAtributo2(rs.getDouble(2));
    objetos.add(obj);
}

então… essa List é retornada e na hora de eu listar numa JTable (por exemplo), itero cada objeto e listo um por um…
ex:

for (Iterator it = objetos.iterator; it.hasNext;) {
     Objeto obj = (Objeto)it.next;
     System.out.println(obj.getAtributo1()+" - "+obj.getAtributo2());
}

só que deste jeito, se tenho 500 registros no banco, a demora para realizar um select e trazer os objetos vai de 10 a 15 MINUTOS!
como faço pra resolver esse problema sendo q o postgres suporta 9223372036854775807 registros numa tabela e nao chego nem ao 600???
ouvi falar num design pattern Fast Lane Reader mas de acordo com o que li ele destrói com a programação em camadas…
[/quote]

Acho que você não lê no lugar certo. O FastLane Reader serve excatamente para não destruir camadas. Leia isto.

O uso do profile é legal mas desnecessário neste caso. O seu problema é a leitura de uma grande quantidade de dados e isso implica directamente no uso do FastlaneReader. O fastlane não tem uma implementação unica que servi para todas as arquiteuras. Vc tem que ver como funciona no seu caso.

Em particular no swing vc tem que entender o conceito de ruberstamp do renders do swing que são desenhados exactamente para que não seja necessário manter todos os objetos na memoria.

foi exatamente aí que eu li…

e de acordo com o site:

já descartei a possibilidade de usar esse design pattern justamente por isso…
estava fazendo outros testes e acho q ainda a melhor maneira para resolver esse problema é fazer paginação…
O problema está nos relatórios, pois é possível o cliente querer resgatar dados de 10 anos atrás e isso implica em um número muito grande de registros que não poderiam ser paginados diretamente…
o mais estranho disso tudo é que depois de vários testes notei algo estranho: resgatei 922 registros (carregando numa JTable em servidor remoto) em aproximadamente 5 segundos… Inseri mais 50 registros (total 972) e o sistema travou completamente na hora de buscar…
por que 922 dados voltam em 5 segundos e 972 nem chegam a retornar??? (detalhe: não há OutOfMemory… nenhum erro é informado… simplesmente TRAVA e não retorna nada…)
POR QUE ISSO??

Pessoal!!
Resolvi o problema liberando mais memória para o sistema…
liberei 1GB e 3000 dados retornaram em menos de 5 segundos (listando em JTable)
mesmo assim vou usar peginação nas telas e orientar o cliente na hora de gerar um relatório com muitos dados (um relatório completo do iReport com 3000 registros dura em torno de 30 segundos a criação)
5500 registros retornaram em aprox. 7 segundos…
realmente era memória (apesar de não dar OutOfMemory)
agora só preciso saber como faço para especificar a quantidade de memória padrão pra cada vez que o sistema rodar…
tem como configurar isso no próprio .jar sem precisar rodá-lo pela console passando os parametros de memória??
estou utilizando o eclipse…
obrigado a ajuda…

Cara, já que o seu problema é só alocação de memória, faça uns testes com o Runtime.freeMemory(), totalMemory(), no meio do seu código. Faça antes e logo após a sua chamada da função que popula o JTable, e faça também depois que a tabela já foi renderizada. Acredito que o seu problema é o excesso de objetos temporários criados nesse processo, pois já que o acréscimo de memória deixou o seu sistema rápido.