Como trabalhar com grandes volumes de dados

707 views
Skip to first unread message

Washington reis de freitas

unread,
Aug 13, 2015, 10:17:04 AM8/13/15
to javasf: JavaServer Faces Group
Bom dia pessoal,  sou iniciante em java e banco de dados. 

Estou desenvolvendo uma aplicação web e meu cliente tem 200mil registros em uma tabela  não sei se isso pode ser considerado um grande volume de dados rs,  
e ele deseja exportar todos esses registros para uma planilha de excel, porém sempre que tento realizar essa operação eu recebo um Java Heap Memory error o glassfish explode ele não guenta. 

Existe alguma boa prática de programação para se trabalhar com grandes volumes de dados em java pessoal?
Não se estou errado mais acho que o excel só aguenta 56mil registros por tabela certo?
Como eu poderia exportar esses registros pra planilhas do excel? eu tentei o dataexporter do primefaces mais daí o navegador também não aguenta.


Se alguém puder me ajudar com essa dúvida e dicas de como posso trabalhar esse volume de dados eu agradeço muitooo!

Obrigado. 

Davi Mustafa

unread,
Aug 13, 2015, 12:02:54 PM8/13/15
to javasf: JavaServer Faces Group
Cara, 200 mil registros o banco aguenta, o excel eu não sei quantos. Ja tentou jogar esses dados em um relatório gerado pelo Ireports?

--
Você recebeu essa mensagem porque está inscrito no grupo "javasf: JavaServer Faces Group" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para javasf+un...@googlegroups.com.
Acesse esse grupo em http://groups.google.com/group/javasf.
Para ver essa discussão na Web, acesse https://groups.google.com/d/msgid/javasf/3a002e5a-04c0-4681-b6a8-f00b909bc6eb%40googlegroups.com.
Para mais opções, acesse https://groups.google.com/d/optout.



--
Davi Mustafa

Everton Fujimoto

unread,
Aug 13, 2015, 12:20:16 PM8/13/15
to jav...@googlegroups.com
1. Banco ou excel, o primeiro gargalo é a configuração da própria máquina/server e a configuração do SGBD. 200 mil registros geralmente é considerado pouco, quase qualquer configuração de hardware e do banco aguenta tranquilo (falando do SGBD)
2. Excel, XLS se não me engano o máximo é 2^16=65536 linhas por planilha (ou seja, num mesmo documento vc pode colocar mais planilhas)
3. Excel, XLSX, se não me engano o máximo é 2^20=1048576 linhas por planilha. 
4. Se você está usando JPA para fazer essa consulta, ele vai trazer todos os registros para a memória, nesse caso podemos:
4.1 Paginar os registros da consulta utilizando JPA mesmo (tem perda de desempenho comparado a próxima alternativa, mas é mais rápido para escrever e mais fácil de dar manutenção). 
4.2 Utilizar "Cursor do banco", mas o JPA não tem esse recurso especificado, então você provavelmente terá que fazer uma Native Query obtendo um ResultSet do JDBC, e iterando usando next(). Essa opção é a mais indicada se vc estiver usando volume de dados muito grande pois não traz os dados para a memória e te permite navegar entre os registros direto da consulta, mas lembre-se, isso causará uso de tempspace do banco, então se for algo crítico, converse com o DBA responsável. 


Att.
Everton William Fujimoto

Rafael Ponte

unread,
Aug 13, 2015, 12:45:43 PM8/13/15
to jav...@googlegroups.com
Olá,

As dicas do Everton foram muito bacanas. O que você precisa ter em mente é que você não pode ou não deveria carregar todos os itens do banco para memória para só então fazer o processamento. Não tem servidor que aguente isso :-)

Faça o carregamento por demanda como explicado pelo Everton. Usar a paginação da própria JPA é o caminho mais simples e provavelmente você não terá dificuldades.

Se performance for de fato um requisito primordial para você então recomendo seguir a dica 4.2 do Everton, porém em vez de SQL nativo você pode usar a API StatelessSession + ScrollableResults do Hibernate para navegar nos itens da tabela via cursor (estou levando em conta que você está usando Hibernate).

Um abraço! 


Para mais opções, acesse https://groups.google.com/d/optout.
--
Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

Washington reis de freitas

unread,
Aug 13, 2015, 1:11:10 PM8/13/15
to javasf: JavaServer Faces Group
Eu não estou usando Hibernate eu estou usando o método tradicional mesmo pra fazer a consulta no banco.

Conexao conexao = new Conexao();
        Connection conn = conexao.getConnection();

        List<Contrato> lstContrato = new ArrayList<Contrato>();
        String sql = "select distinct * from sgm_contrato_tmp" + sClausula.montarsClausula();
        PreparedStatement ps = conn.prepareStatement(sql);
        System.out.println(sql);

        ResultSet rs = ps.executeQuery();

        System.out.println("passando pelo DAO:");

        Contrato contrato;
        while (rs.next()) {
            contrato = new Contrato();
            contrato.setMissionario(rs.getString("Nome"));
            contrato.setValor(rs.getDouble("valor"));
   ...//aqui eu pego as colunas do banco de dados
 listaContrato.add(contrato);
//e armazeno todos esses 200mil registros dentro de um ArrayList e dai eu trabalho em cima desse arrayList pra criar uma planilha de excel

Eu tentei criar um DataTable com paginator e tudo com a propriedade value="#{contratoController.listaContrato}"  porém nem assim eu consigo carregar no dataTable.
Estou utilizando JSF 2. 

Everton Fujimoto

unread,
Aug 13, 2015, 1:42:07 PM8/13/15
to jav...@googlegroups.com
Pontes, já tinha lido sobre esse scrollableresult do Hibernate mas nunca utilizei, funciona bem? É nessas horas que a gente sente falta da Deferred Query Execution do .net... rsrsr

Cara, precisa jogar os 200 mil registros na tela? Se precisar, a estratégia precisa ser a mesma que mencionei na 4.2, montar a tabela com dados tão logo busca o registro na base de dados sem armazenar numa lista antes... (você poderia, por exemplo, criar uma classe que herda List e monta o objeto para retornar baseado na consulta... Mas terá que trabalhar com o padrão "OpenSessionInView"). 

Outra alternativa (mas dá muito mais trabalho) é fazer um Ajax Lazy Scroll Pagination (Ex: http://infiniteajaxscroll.com/examples/basic/page1.html , se precisar mesmo ser por scroll), que conforme você rola a tabela para baixo ele vai fazendo consultas Ajax e populando a tabela. Vai ter que tratar isso "na mão", fora dos recursos padrões do JSF. 

Ou, a mais indicada, é usar uma paginação com números de páginas... está usando alguma biblioteca "Rich Internet Application" como Richfaces ou Primefaces? Se tiver bem provável que ele já tenha esse recurso. 


Att.
Everton William Fujimoto

--
Você recebeu essa mensagem porque está inscrito no grupo "javasf: JavaServer Faces Group" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para javasf+un...@googlegroups.com.
Acesse esse grupo em http://groups.google.com/group/javasf.

Davi Mustafa

unread,
Aug 13, 2015, 1:44:55 PM8/13/15
to javasf: JavaServer Faces Group
ja tentou usar o lazy loading do primefaces?

Em 13 de agosto de 2015 14:11, Washington reis de freitas <was...@gmail.com> escreveu:

--
Você recebeu essa mensagem porque está inscrito no grupo "javasf: JavaServer Faces Group" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para javasf+un...@googlegroups.com.
Acesse esse grupo em http://groups.google.com/group/javasf.



--
Davi Mustafa

Rafael Ponte

unread,
Aug 13, 2015, 1:48:18 PM8/13/15
to jav...@googlegroups.com
Oi,

Funciona sim! Pode usar sem medo :-)


Para mais opções, acesse https://groups.google.com/d/optout.

Henrique Neto

unread,
Aug 13, 2015, 2:56:17 PM8/13/15
to jav...@googlegroups.com
Washington,

acho que seria melhor você ver os pontos que o Rafael Ponte falou. Será que realmente é necessário carregar todos os 200k registros? Porque alguem precisaria de um Excel com todos esses registros? Acredito que seria melhor rever o requisito antes de procurar uma solução técnica para algo que talvez você nem precise.



Att.,
Henrique Neto
Graduado em Análise e Desenvolvimento de Sistemas
Pós-Graduando em Engenharia de Software
LPIC-1 -  ID: LPI000243620 Verification: tmlvhgun7h
Oracle Certified Java Programmer 6
"Dizem que o tempo muda tudo, mas não é verdade. Fazer coisas é que muda
algo, não fazer nada deixa as coisas do jeito que estão."
Gregory House


Washington reis de freitas

unread,
Aug 13, 2015, 3:48:30 PM8/13/15
to javasf: JavaServer Faces Group
É eu particularmente não acho interessante ter 200mil registros em uma planilha do excel, mais é isso que o cliente quer  e daí eu preciso encontrar uma solução, eu agradeço pelas respostas vocês são demais muitas ideias e pra mim que sou iniciante vejo que tenho um longo caminho pela frente!  irei estudar sobre essa solução que o Rafael Pontes comentou do  Hibernate. 
A eu não preciso jogar os registros pra tela não só gerar o excel mesmo, o problema é gerar esse excel pois preciso desses registros dentro de uma lista e daí trabalhar pra gerar a planilha, mais um ArrrayList não guenta todos esses registros estou correto?

Em quinta-feira, 13 de agosto de 2015 11:17:04 UTC-3, Washington reis de freitas escreveu:

Rafael Ponte

unread,
Aug 13, 2015, 3:55:07 PM8/13/15
to javasf: JavaServer Faces Group
Oi,

Se você não usa Hibernate então use JDBC puro mesmo. Com ele você pode fazer paginação ou usar cursors.

--
Você recebeu essa mensagem porque está inscrito no grupo "javasf: JavaServer Faces Group" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para javasf+un...@googlegroups.com.
Acesse esse grupo em http://groups.google.com/group/javasf.

Para mais opções, acesse https://groups.google.com/d/optout.

Everton Fujimoto

unread,
Aug 13, 2015, 5:59:40 PM8/13/15
to jav...@googlegroups.com

Uma sugestão Washington, se vc não vai exibir na tela, não seria mais prático vc instalar um driver odbc na máquina do seu cliente e fazer o Excel consultar direto o Banco de dados? Dependendo da situação pode ser mais vantajoso, por exemplo, tabela dinâmica através de odbc não tem o limite na quantidade de linhas de dados que a planilha tem, Tem melhor desempenho que ela funcionar sobre uma planilha e basta o seu cliente clicar com o direito nela e" atualizar dados" para fazer a consulta novamente... as vezes soluções em microinformatica são mais rápidas e versáteis...

Everton Fujimoto

unread,
Aug 13, 2015, 6:09:54 PM8/13/15
to jav...@googlegroups.com

Obs, Não é que o ArrayList não aguenta.. é que vc vai subir tudo isso na memória.... se esses 200 mil registros ocuparem 20k na memória cada, vc precisaria 40MB só para subir os elementos da lista na memória, e mais uns MB para o ArrayList referenciar eles... se vc quiser seguir por esse caminho, vc aumenta o parâmetro de inicialização da sua jvm Xmx (dá uma procurada no Google, estou no celular) que vc vai conseguir subir todos os 200 mil registros na ArrayList, mas isso provavelmente vai ter um péssimo desempenho e quando seu cliente passar a ter 300 mil registros... vai consumir mais memória que somente os 50% a mais....

Vc está usando jdbc, para montar o xls esta usando o q? Apache poi.? É só iterar no resultset como vc já itera, mas ao invés de popular o ArrayList vc já grava isso no xls.

Obs, as bibliotecas que conheço de xls sobem o xls inteiro na memória bem como também grava o xls de uma vez só... então talvez ainda te de esse problema de Java heap space pois o xls ainda vai estar na memória... se for esse o caso, procura alguma lib para trabalhar com xls através de stream e se não encontrar, grava num xml e faz uma.macro num xls para ler o xml...

felipe bento

unread,
Aug 14, 2015, 8:42:58 AM8/14/15
to jav...@googlegroups.com

Eu tinha uma base no Oracle e o cliente pediu para ver uma tabela no excel, tinha cerca de 168 mil registros eu exportei para .CSV( se nao me engano, pois faz  um tempo que fiz isso) e abri no libre office. Deu certo.

Rafael Ponte

unread,
Aug 14, 2015, 8:51:15 AM8/14/15
to jav...@googlegroups.com
Washington,

Todas as dicas aqui foram super válidas e você deveria ouví-las. Mas tenha em mente que seu problema principal não é com relação as técnicas que podem der utilizadas nem performance, mas sim com o princípio básica desta problemática: você não pode nem deveria carregar para memória todos os objetos do banco. Isso precisa ser feito por demanda, ou seja, enquanto lê algo do banco você já escreve em disco (.csv) e, por fim, libera da memória aquele objeto carregado.

Há grandes chances de você não ter problemas de performance ou, mesmo que tenha, o tempo para processar essa planilha seja aceitável para seu cliente. Dessa forma, não se preocupe com isso ainda! Faça a funcionalidade rodar.

Esse tipo de problema é muito comum no desenvolvimento de software, principalmente em aplicações Web onde vários usuários podem gerar relatórios pesados e custosos ao mesmo tempo. Se sua aplicação levar uma grande massa de objetos para 1 usuário (como já disseram, 40mb), imagina para 50 usuários em horário de pico.

Um abraço.



Para mais opções, acesse https://groups.google.com/d/optout.

Washington reis de freitas

unread,
Aug 14, 2015, 1:01:42 PM8/14/15
to javasf: JavaServer Faces Group
Everton Consegui !!!!

Fiz o que você falou eu estava populando um ArrayList no meu ResultSet  dentro do while(rs.next) { }, ao invés de popular o arrayList pra depois trabalhar na criação da planilha do excel eu fiz a criação linha por linha da planilha do excel dentro do próprio resultset 
utilizando a lib HSSFWorkbook e HSSFSheet e ai dentro do while(rs.next) {  
 HSSFRow linha = sheet.createRow(contador);
 HSSFRow cabecalho = sheet.createRow((short) 0);
 cabecalho.createCell(0).setCellValue("NOME");
 linha.createCell(0).setCellValue(rs.getString("NOME")); 
}  

dai eu criei um contador pra quando chegar a 65mil ele criar uma nova planilha e continuar adicionando linhas de onde parou...
e funcionou!!! e a criação da planilha durou apenas 20 segundos !  
Obrigado a todos pelas dicas vocês são demais!!  

A sim eu tive que aumentar a JVM heap Memory pra 1024m !! 


Em quinta-feira, 13 de agosto de 2015 11:17:04 UTC-3, Washington reis de freitas escreveu:
Reply all
Reply to author
Forward
0 new messages