Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Consulta Hibernate e Postgres

Olá, eu uso no meu sistema o Hibernate JPA 2 e o Postgres.

Tenho uma entidade na minha aplicação que possui muitas colunas. É uma entidade que fica salvo as baixas pagamentos da empresa.

Essa entidade tem muitas colunas que são @ManyToOne, e como sabemos as colunas *ToOne são carregadas de forma EAGER por padrão.

Conforme o crescimento da entidade me deparei com o seguinte erro "target lists can have at most 1664 entries". Que diz que o select criado possui mais de 1664 colunas.

Exibi a consulta do Hibernate, e percebi que o mesmo criava uma consulta enorme, pois cada ToOne que encontrava ele inicializava, e dentro da entidade inicializada o hibernate inicializava cada ToOne dentro dessa outra entidade, sendo assim, por ter muitos campos *ToOne com muitas dependências o erro ocorria.

Eu resolvi o problema colocando alguns campos *ToOne da entidade para fetch Lazy.

Pergunta 1: Gostaria de saber se essa é a forma ideal para resolver o problema, ou se existe alguma outra solução mais adequada?

Encontrei em alguns fóruns essa solução (que para mim não funcionou) que deveria ser posto no persistence.xml, que segundo o que eu li, define quantas collections deverão ser carregadas juntando todos aqueles SELECTS em uma clausula “IN”.

Pergunta 2: Gostaria de saber se deixar isso no código é uma boa prática, ou se isso pode deixar o sistema mais lento? Se alguem souber mais detalhes sobre isso.

Também li a respeito de trabalhar com listas OneToMany com @Fetch(FetchMode.SUBSELECT), no entanto não entendi no que isso ajudaria no sistema, Pergunta 3: Alguém que entender sobre isso pode me explicar se isso é uma boa prática trabalhar com Fetch SUBSELECT e em quais momentos devo utilizar?

2 respostas
solução!

Oi Rafael,

A boa prática é sempre marcar todos os relacionamentos *ToOne, de todas as entidades, com FETCH=LAZY. Isso evita um problema chamado N+1 Select, que é bem comum nas aplicações, e causa serios problemas de performance.

E sempre que você for carregar uma entidade para exibir em alguma tela, você monta o JPQL carregando apenas as informações que são necessárias, evitando assim selects desnecessários. Dá para utilizar o JOIN FETCH nas queries, para carregar os relacionamentos.

No seu caso, acredito que o ideal seria montar uma query customizada, utilizando o mecanismo conhecido como Select new da JPA, pois assim você consegue controlar cada coluna de cada relacionamento que deseja carregar, e evita carregar dados desnecessários.

Outra coisa, o @Fetch(FetchMode.SUBSELECT) é específico do Hibernate e não da JPA.

No seu caso, que a entidade tem muito atributos, você pode utilizar também um mecanismo para nos updates atualizar apenas as colunas que sofreram alteração, evitando assim um update das trezentas milhões de colunas no banco. Bata anotar a entidade com @DynamicUpdate, mas esse recurso também é específico do Hibernate.

Bons estudos!

Obrigado rodrigo as informações foram muito úteis.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software