Imagine a seguinte tarefa:
Criar duas telas para um blog, a primeira lista as categorias dos posts, junto com a quantidade de posts de cada categoria, a segunda lista todos os posts de uma categoria, com paginação e por padrão ira mostrar 20 posts por página …
para isto você tem ja pronta a seguinte estrutura:
Qual é o exemplo padrão para listar os posts de uma categoria com paginação?
Código do servlet:
Categoria c = entityManager.find(Categoria.class,1);
request.setAttribute("categoria",c);
request.setAttribute("posts",c.getPosts());
request.getRequestDispatcher("/resposta.jsp").forward(request,response);
Código da tabela com paginação:
<h2>${categoria.nome}</h2>
<display:table name="posts" pagesize="10"/>
Isto vai fazer o que foi solicitado, que é mostrar de uma forma paginada, os posts da categoria de id=1 (eu fixei o ID para simplificar o exemplo)
Quais quais os prováveis problemas de performance você já identificou?
Nenhum ainda?
Este tipo de código é bastante comum de se ver por ai, por este tipo de código digo, buscar todos os registros e paginá-los depois …
Inclusive em algumas situações (semana passada), por facilidade eu fiz coisa bem parecida (claro que este é um exemplo simplista, mas não é este o ponto) …
Qual o problema então?
Imagine uma categoria com 100.000 posts …
Cada vez que a página for carregada vai acontecer o seguinte:
Ou seja, isto é um desperdício de processamento e memória, que consome tempo do usuário …
Este ciclo todo vai ocorrer novamente quando o usuário pressionar o numero da página desejada também, que vai novamente entulhar a memória de lixo que não vai ser utilizado …
Isto não é uma critica a display tag, e sim aos programadores (eu incluso, pois como comentei fiz parecido em um sistema, e passei dois dias esta semana corrigindo isto).
E como resolver?
Buscar do banco de dados apenas os registros que serão utilizados …
Claro, isto vai requerer no mínimo duas consultas, uma para trazer o conteúdo e outra para trazer a contagem total de registros …
Mas a melhora é visível na performance de acesso a esta tela …
E como implementar isto com display tag?
Tem duas opções:
utilizar os atributos da tag partialList e size (claro que fazendo isto você precisa fazer ordenação externa também se quiser algma coluna ordenavel na tabela) e utilizar o helper da display tag para descobrir qual o primeiro registro a ser mostrado:
(Integer.parseInt(request.getParameter((new ParamEncoder(tableId).encodeParameterName(TableTagParameters.PARAMETER_PAGE)))) - 1) * pageSize
ou retornar em vez de uma collection uma implementação da interface org.displaytag.pagination.PaginatedList
Mas se você estiver utilizando por exemplo o paginator do tomahawk com JSF então boa sorte pois ele não tem um suporte muito bom para este tipo de coisa …
No caso de JSF+EJB3 acho mais indicado utilizar algo parecido com o p4j5, ou então não utilizar nenhum dos componentes de paginação prontos que eu conheço para JSF
Então, vocês escrevem código parecido com isto? (trazer um monte de registros e paginar só na view)
Conhecem gente que faz isto?
Que outras coisas vocês acham que fazem ou que viram fazer (as vezes colocar a culpa nos outros facilita o comentário
) que são visivelmente um problema grave de performance quando a aplicação sai do ambiente de testes?
Digo quando sai do ambiente de testes por que mesmo o exemplo citado em um ambiente com poucos dados não apresenta problema algum …
E de quem é a culpa deste tipo de código ser tão comum por ai?
Na minha opinião, é da falsa sensação de programação statefull que temos programando com a grande maior parte dos componentes disponíveis por ai …
Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!
Passei por esse problema há algumas semanas. Aqui utilizo a lógica de negócios numa camada de EJBs e a view com JSF (Woodstock) em outra. Uso o table do woodstock que se alimenta de um DataProvider que se alimenta de um List.
O fato é que precisava fazer uma consulta que retornaria um número absurdo de registros. Minha primeira opção foi especializar o DataProvider de forma a ele ter a inteligência para paginar os dados, mas aí não funcionava adequadamente o table. Se vc ainda nah viu esse componente em ação, ele possui controles p sorter e pagination nele próprio. As informações para compor isso vem do proprio List (tamanho total e o consequente número de páginas).
Então achei nesse post http://www.ninthavenue.com.au/blog/lazy_list uma solução interessante! Colocar o mecanismo de paginação na própria List! Ou seja, o size dela retornaria o total da consulta, mas ela manteria somente os x registros lidos (onde x é o tamanho da página de dados, não necessariamente o tamanho da página mostrada). Quando o componente pedir um registro q ela não tem, submete nova consulta!
Implementei aqui com algumas ressalvas, uma vez q por ter separado em duas camadas distantes, eu não posso manter sessão aberta ou usar uma query como ele usou. Na verdade, eu passo p lista o serviço e os métodos q ela deve utilizar p pegar o count e os registros paginados.
No fim das contas, passo essa list p o dataprovider e o provider p o table woodstock. Para eles é tudo normal e agem como se fora um List full. Works like a charm!
Mas como nada na vida é simples, agora surgiu a necessidade de TOTALIZAR algumas colunas da table! Ou seja, preciso de uma terceira chamada ao banco (ou alterar o método do count) para saber os totais das colunas dadas. Acho que encapsulando tudo isso daria um belo componente JSF! =)
Btw, nice post!
Reply to this commentUrubatam, agradeço pelo Post o qual apresenta um problema em potencial, ainda mais para um iniciante como eu, você não poderia apresentar um exemplo simples de como o problema pode ser resolvido? Estou usando JSF aqui, mas como vc disse em ambiente de teste isso é impercebível.
Já procurei essa solução em vários forums e não encontrei, poderia ajudar-nos?
Forte abraço,
Reply to this commentA solução que o Rodrigo postou no comentário anterior funciona bem com JSF
Reply to this commentSera que vc não poderia montar um exemplo simples e mais trivial para a gente poder aprender?
Reply to this commentIsso aqui pode ajudar para paginar sobre demanda,
http://wiki.apache.org/myfaces/WorkingWithLargeTables
Abraços.
Reply to this commentRealmente eu já fiz isso no começo, quando ainda tava aprendendo sql. + depois descobri que havia 2 parametros que são passados na consulta select (LIMIT e OFFSET) que restringem a quantidade de registros retornadas pela consulta. Acho que isso hoje em dia já não é + problema pq se tornou padrão. Existem vários módulos para isso disponíveis em várias linguagens pela net afora!
em todo caso muito obrigado pela dica
Reply to this comment[...] possui uma implementação simples e não se preocupa com alguns requisitos não funcionais como a paginação sob demanda ou quais os objetos que deveriam permanecer entre as requisições. Além do mais o exemplo é um [...]
Reply to this commentOlá Urubatan, parabéns pelos trabalhos que vc tem desenvolvido, por várias vezes resolvi problemas com as suas explicações. Agora tenho uma dúvida, estou utilizando o netbeans 6.1 e estou tentando acessar mostrar meus dados na table do woodstock porém não conheço bem o componente. Será que vc poderia me dar uma luz. O sistema antigo que eu tenho eu utilizei o tomawalk, ja tenho uma noção muito boa!!!! obrigado!!!!!
Reply to this comment