Performance JPA e TopLink

Bom dia amigos,

Ha algum tempo desenvolvi pequenas aplicações utilizando JSF , JPA , TopLink com Oracle e para estas aplicações não encontrei problemas de performance. Porém , recentemente criei uma aplicação que exige um pouco mais de recurso , pois trata-se de um maior volume de dados e de acessos. Ao meu ver , considerando todos esses pontos acredito que a aplicação tem uma performance relativamente boa, mas para excluir qualquer dúvida gostaria de saber se existe algo que eu possa fazer para melhorar.

Existe alguma dica para melhorar a performance ? Minha entity principal é está:


@Entity
@Table(name = "ASCHAMADO")
@NamedQueries({
    @NamedQuery(name = "AsChamado.searchAll"         , query = "select a from AsChamado a order by a.idChamado desc "),
    @NamedQuery(name = "AsChamado.searchById"        , query = "select a from AsChamado a where a.idChamado = :idChamado"),
    @NamedQuery(name = "AsChamado.searchBySolicOrDig", query = "select a from AsChamado a JOIN a.solicitante b JOIN a.digitador c where a.dataChamado between :dataInicio and :dataFim and ( b.idUsuario = :idUsuario or c.idUsuario = :idUsuario ) order by a.idChamado desc"),
    @NamedQuery(name = "AsChamado.searchByPeriodo"   , query = "select distinct a from AsChamado a JOIN a.AsAtendenteChamado b where a.dataChamado between :dataInicio and :dataFim and :atendente is null or b.atendente.idUsuario = :atendente order by a.idChamado desc")
})
public class AsChamado implements Serializable {

    @Id    
    @Column(name = "ID_CHAMADO", nullable = false)    
    private long idChamado;
    
    @ManyToOne
    @JoinColumn(name = "EMPRESA_PROP", nullable=true, insertable=false,updatable=false, referencedColumnName = "ID_EMPRESA_PROP")
    private UsEmpresaProp empresaProp;
    
    @ManyToOne
    @JoinColumn(name = "DIGITADOR", referencedColumnName = "ID_USUARIO")
    private AsUsuario digitador;

    @ManyToOne
    @JoinColumn(name = "SOLICITANTE", referencedColumnName = "ID_USUARIO")
    private AsUsuario solicitante;

    @ManyToOne
    @JoinColumn(name = "TIPO_CHAMADO", referencedColumnName = "ID_TIPO_CHAMADO")
    private AsTipoChamado tipoChamado;

    @Column(name = "DATA_CHAMADO", nullable = false)
    @Temporal(javax.persistence.TemporalType.TIMESTAMP)
    private Date dataChamado;

    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "SISTEMA" , referencedColumnName = "SISTEMA"  ,nullable=true),
        @JoinColumn(name = "MODULO"  , referencedColumnName = "MODULO"   ,nullable=true),
        @JoinColumn(name = "OPERACAO", referencedColumnName = "OPERACAO" ,nullable=true)
    })
    private AsModuloOperacao moduloOperacao;
    
    @ManyToOne
    @JoinColumn(name = "PRIORIDADE", referencedColumnName = "ID_PRIORIDADE")
    private AsPriorChamado prioridade;

    @Column(name = "DESCRICAO", nullable = false)
    private String descricao;
    
    @Column(name = "DESCRICAO_SEM_FORMATACAO", nullable = false)
    private String descricaoSemFormatacao;

    @ManyToOne
    @JoinColumn(name = "STATUS", referencedColumnName = "ID_STATUS")
    private AsStatusChamado status;

    @Column(name = "DATA_NECESSIDADE", nullable = false)
    @Temporal(javax.persistence.TemporalType.TIMESTAMP)
    private Date dataNecessidade;

    @ManyToOne
    @JoinColumn(name = "CHAMADO_EXTERNO", referencedColumnName = "ID_CHAMADO", nullable = true)
    private SuChamado chamadoExterno;

    @Column(name = "CHAMADO_REF")
    private long chamadoRef;
    
    @Column(name = "FG_LIB_APROV_TI", nullable = false)
    private String fgLibAprovTi;
    
    @OneToMany( mappedBy="chamado" )
    private List<AsEstagioAprovacao> asEstagioAprov;

    @OneToMany( mappedBy="chamado" )
    private List<AsChamadoHistObs> asChamadoHistObs;

    @OneToMany( mappedBy="chamado" )
    private List<AsAtendenteChamado> AsAtendenteChamado;

    @OneToMany( mappedBy="chamado" )
    private List<AsChamadoLog> asChamadoLog;

    @OneToMany( mappedBy="chamado" )
    private List<AsTarefaChamado> asTarefaChamado;

    /*GETS E SETS*/

As outras entitys foram construidas da mesma forma. O que vocês me dizem ?
É isto mesmo ou ainda posso melhorar ?

Obrigado pela atenção dos senhores.

Boa noite amigos,

Alterei a forma de me conectar ao banco e obtive uma excelente performance. Uso o TomCat com o pool de conexão.
Se alguém passar pelo mesmo problema estou a disposição.

Obrigado e abraço a todos.

Olá,

Uma outra coisa que vc poderia verificar é sua estratégia de Fetch.

O Default é FetchType.EAGER, ou seja, a sua implementação do JPA vai fazer join com todas as tabelas necessárias (de acordo com o mapeamento de sua entidade, nesse caso pelos uns 8 joins estão sendo gerados, correto ? )

Acredito que vc nao precise de tudo logo de cara, especialmente seus OneToMany. Obviamente isso pode estar errado, dependendo do seu layout.

Mas gostaria que vc fizesse um teste, use seus OneToMany(fetch = FetchType.LAZY ) Isso vai fazer com que o join não seja feito inicialmente e a busca seja realizada somente quando o dado for necessário de fato.

Uma vez mais ressalto que dependendo da forma como vc usa esse objeto isso pode até piorar a performance, mas sinceramente duvido q vc exiba tanta informação de uma única vez.

De qualquer forma, por não ter visto nenhuma das entidades como Lazy imaginei que vc não conhecesse esse atributo.

Espero ter ajudado.

Abs

Olá,

Quando eu comecei a enfrentar problemas com a performance, nas minhas pesquisas sobre esse assunto eu encontrei muitos tópicos falando sobre este atributo. Realmente até então eu não o conhecia.

Mas eu não os coloquei , porque na documentação da versão do JPA que estou usando ele indica que o default já é o Lazy como mostra a figura abaixo:

Será que está correto ? Vou colocar o atributo para ver se noto alguma diferença. De qualquer forma, acho que a minha grande falha era não estar trabalhando com o POOL de conexões. Estou surpreso com o ganho de performance.

Desde já agradeço a atenção.
Obrigado.

Caro Iblanco,

Sou programador C# e estou algum tempo estudando java, queria desenvolver um projeto
q dois amigos e eu temos e achei bom q fosse multiplataforma.

Tudo estava indo muuuuuuuuuuito bem, gostei muito do JPA, tem recursos q o EF n tem, só
que travei nisso, em testes q eu fiz de consulta que traziam grande volume de dados, o
conjunto JPA + TopLink pecou!!! Putz, pra minha tristeza, pois eu já estava decidido a realmente
fazer o projeto em Java, só q a diferença foi grande.

Vc testou algo assim, tipo, uma consulta q retorne, por ex., 10.000 registros?
Nos meus testes, (claro q depende das conf das maquinas), mas demoraram semrpe mais de
15 segundos.

Vez ou outra eu olho tópicos como este pra v se há algo novo vindo por aí, pelo menos.

Se puder dar umas dicas, e melhorar, volto pro Java :smiley:

UpTheIrons,

Primeiramente gostaria de dizer que não faço apologia a nenhuma linguagem de programação. Defendo que a tecnologia deve estar voltada para atender de melhor forma a necessidade do cliente. Sendo assim, para cada projeto faço uma avaliação das possiveis tecnologias disponiveis e só entao faço a minha opção.

Bom… tudo isso pra dizer que nao sou puxa saco de nenhuma linguagem de programacao. Agora falando do java … especificamente da arquitetura que vc mencionou… eu tenho um projeto grande utilizando TOPLINK, JPA, JSF, RICHFACES E ORACLE. Esse projeto iniciou-se com 6.000,00 mil registros grandes … e com um mes de funcionamento já deve estar bem maior e depois de algumas otimizacoes esta bem rapidinho.

Nao sou especialista nisso mas posso aconselhar que:

1 - Faça os mapeamentos das classes de forma correta ( Analisando os seus atributos Lazy … )
2 - Utilize um pool de conexao , isso dará uma performance e tanto para a sua aplicação.
3 - Não use critéria para buscar os dados do banco.
4 - Utilize um bom banco de dados ( Oracle / Postgres ) são os que já trabalhei.

Enfim, nao tenho muito mais o que dizer.
Se precisar de alguma coisa me dá um toque aí.

Abraços.

Caro Iblanco,

Já defendi muito uma linguagem sem conhecer outras, isso n faço mais, e cada uma tem suas próprias vantagens…

Vc disse q o banco tá com 6000 registros… blz, o que fiz na verdade foi preencher duas tabelas, cada uma com
100.000 registros. Até aí, blz, não tinha percebido diferença entre Java com Postgre, Oracle e SqlServer, tanto no
windows qto no linux e o .Net com SqlServer.

Os mapeamentos estão tranquilos, pois fiz apenas duas tabelas cada uma com apenas 4 campos.
Fiz consultas em uma única tabela como também com as duas (join).
O problema não está aí, a n ser que tenha algum recurso no coelho da cartola q ainda n vi :slight_smile:

Mas assim, pra fazer consultas de até 1000 registros, detalhe, não estou falando em fazer uma consulta num
banco com 1000 registros e sim trazer os 1000 registros (relatórios por ex), então, com 1000 tá tudo bem,
só q pra 10.000 á diferença aumenta significativamente, é isso q quis dizer. Ressaltando que n fiz qq
consulta complexa, nos dois casos são SELECTs simples.

Não estou defendendo uma ou outra, como falei, sou programador C#, desenvolvi um aplicativo em Java
com Postgre para a empresa em que trabalho, e hj está lá, rodando no Ubuntu, uma blz.
Queria desenvolver esse outro projeto q falei, mas ele vai exigir relatórios imensos (entre 8.000 e 12.000 registros)
e por isso fiz uns testes… e neste quesito complicou um pouco, pois foi um fato que me fez decicir n continuar
o projeto em Java (JPA).

Outro detalhe, estou falando de aplicativos Desktop.

Resumindo, não estou falando mal de uma ou de outra, mas como uma pode ser melhor q outra em casos específicos,
apresentei meu caso e, que se houvesse algum detalhe q mudaria isso, eu continuaria com Java para o projeto, o que não
quer dizer q não utilizarei mais o Java para outras aplicações.

Abração!

Mas vamos lá…
O testes q fiz foram pensando no seguinte:

Humm , entendi…

Pensamos da mesma forma. Bom, nao tenho muito que acrescentar o que posso dizer é que acho que ainda dá pra fazer usando Java. Para os relatórios eu aconselho você a utilizar o Jasper Reports, excelente e free.

Do mais, nao tem nenhum segredinho não. Não que eu saiba rsrsrs.
Acho que raramente voce ira trabalhar com milhares de registros de uma unica vez, em memoria. Geralmente para as consultas existem datas como filtros enfim…

Vou tentar ser mais direto.
Se voce usar oracle, ja tem um grande ganho.
Com JPA nao tive problema usando o pool de conexao para trabalhar com 5.000 mil registros.
acho que dá pra rolar blz hein !

Bom, é o seguinte gostaria de entender como criar namedqueries que envolvam notações manytoone.
Vou explicar:
Possuo uma base de dados dos correios, e a princípio fiz todo o uml conforme eu adaptei a minha base para o meu sistema.
Porém entenda a seguinte situação: um estado possui vários municípios correto?
Bom partindo desse princípio adptei as classes de acordo com o banco assim como algumas coisas do banco estão adaptadas ao meu sistema.
esta é a classe Uf.java----> http://pastebin.com/m42904ac6
esta é a classe Municipios.java----> http://pastebin.com/m33b13b69
Esta dúvida me surgiu pelo fato de estar programando um jdialog aonde assim que eu selecionar o jcombobox de uf, seje adicionado logo em seguida um segundo jcombobox aonde estão listados apenas os municípios do primeiro jcombobox.
Porém estacionei e não consegui ir adiante quando o assunto foi fazer uma consulta que envolvesse mantoone.
Muito obrigado desde já