Executando uma consulta mas o JPA roda várias

Eu tenho uma consulta em JPQL que quando é executada vejo no console do eclipse que várias outras consultas são disparadas junto com a principal.

List<Object[]> resultado = query.getResultList();

É exatamente nesta linha, que dispara o JPQL, assim que passa por ela começa a rodar vários outros JPQLs. Aparentemente são várias consultas para cada linha de resultado da principal.

Gostaria de saber o que é isso e se há uma maneira de evitar, pois está onerando demais a performance.

1 curtida

Para piorar a situação:
Estiva lendo nos sites e descobri que este problema é chamado de N+1.
Uma das soluções seria usar “FETCH”, mas estranho a consulta já está com esta clausula.
Outra solução é separar as consultas, mas as condições para trazer os dados envolvem todas as tabelas.
Não sei se tem como separá-las

1 curtida

Tem situações que é melhor você escrever uma query nativa do que depender do JPA.

Essas situações são raras. A maioria dos problemas com JPA é porque as pessoas não fazem a minima ideia do que estão fazendo e colocam EAGER em todo o lado e fazem queries a obter mais do que o que precisam.

1 curtida

Bom dia,

De volta com esta query.
Não foi possível por em prática a Query Nativa por questões de padrão na empresa.
Estou, trabalhando com JPA numa versão do java 7 com banco de dados ORACLE

Esta é a query:

SELECT inte.*, desd.* FROM TAB_INTEGRA inte 
		 INNER JOIN TAB_TOP top ON inte.ID_TOP = top.ID
		 INNER JOIN TAB_ORGANIZACAO org ON top.ID_ORG = org.ID_ORG
		 LEFT OUTER JOIN TAB_MIGRA migr ON top.ID_MIGR = migr.ID_MIGR,
		 TAB_DESDOBRAR desd
		 INNER JOIN TAB_ENQUADRAR enqua ON desd.ID_ENQUADRAR = enqua.ID_ENQUADRAR
		 WHERE 1 = 1
		 AND inte.ST_INTEGRA = 1
		 AND (org.DT_VIGENCIA IS NULL) 
		 AND inte.ID_INTEGRA_TIPO = 0
		 AND ait.CD_ENQUADRAR = enqua.CD_ENQUADRAR
		 AND ait.CD_DESDOBRAR = desd.CD_DESDOBRAR 
		 AND (trunc(top.DT_INFRACAO) BETWEEN enqua.DT_INI_ENQUADRAR  
                                                                                       AND  enqua.DT_FIM_ENQUADRAR)
			AND (migr.ID_MIGR IS NULL 
		      OR migr.ID_MIGR NOT IN ( 
                                                  SELECT migra.ID_MIGRACAO 
		                                   FROM TAB_MIGRA migra
		 	               		    INNER JOIN TBPRE_ETAPA_MIGRA eta 
		 		                                         ON migra.ID_MIGR = eta.ID_MIGR
		 		                   WHERE eta.ETAPA_ANDAMENTO = 'S' 
		 				  AND (eta.ID_ETAPA_MIGR_TIPO IN (1,2,3)) 
		                                   OR eta.ID_ETAPA_MIGR_TIPO = 7 
		                                   AND eta.ST_ETAPA_MIGR <> 0 
		                                   OR eta.ID_ETAPA_MIGR_TIPO = 7 
		                                   AND eta.ST_ETAPA_MIGRA <> 0 
						) 
		    ) 
AND org.ID_ORG IN (2981, 5818, 5824, 5826, 5880, 5896, 5989, 6025)
ORDER BY inte.DT_EVENTO, inte.ID_TOP 

A query está com nomes de campos e tabelas fictícios.
Se constatarem algum erro no SQL é erro que cometi ao transporta-la para cá.
Ela funciona, demora mais funciona.
Eu fui retirando tabela por tabela para saber onde estaria a demora.
Cheguei nesta: TAB_INTEGRA
Ficou só: SELECT * FROM TAB_INTEGRA
Quando entra na linha Query.ResultSet fica um tempão pensando.
Quando starta, começa a fazer outros SELECTS * “que não tem nada haver com a TAB_INTEGRA”.
Eu já ví os relacionamentos da tabela, e não tem nenhuma relacão com as que falo acima *
Já foi verificado o banco para saber se há algo errado e nada foi constatado.
O select da TAB_INTEGRA no SQLDeveloper roda de boa.
Bom devo estar pedindo que se passe um quadrado num circulo. “Impossível”.
Mas a minha esperança é que possa ser algo do tipo que alguém fale: Quando acontece isso vc
precisa alterar tal código, quero dizer, algum problema pontual que se faz quando há um comportamento desses.
Se ninguém puder dar uma opinião porque realmente é impossível, não tem problema algum porque sei que é uma sinuca de bico.
Obrigado.

Quantas linhas tem essa tabela?
Como estão as anotações da tua classe que mapeia com a tabela TAB_INTEGRA? Há fetch EAGER?

A tabela tem 267770 linhas das quais neste select retorna 1500 a 2000
Na classe todos os FetchType estão como LAZY

Aqui vai retornar as 267770 linhas. No SQL developer faz fetch de apenas algumas linhas e conforme fazes scroll, faz fetch de mais. No teu código se não tens qualquer lógica de paginação vai fazer fetch de todas as linhas de uma vez. Daí o “tempão” que fica pensando.

Com todo o respeito, isso é coisa de empresa que não sabe o que faz.

Não tem problema, a gente tem que trabalhar com as adversidades.

Bom dia pmlm,
Esta consulta, se entendi direito sua resposta, não será apresentada na tela como resultado.
esta consulta faz parte de um JOB que roda todo dia.
A cada linha de resposta, será feito um processamento alterando esta e outras tabelas.
O limite para processar é cerca 1600 a 2100 linhas.
O problema é que pelo fato de demorar muito, acontece o timeout.

Independentemente de apresentar na tela ou nao, estas a obter os dados da BD para a tua aplicação, certo? Tens de esperar que esses dados sejam consultados na BD e chegam a uma lista tua na aplicação.
Já verificaste se do lado da BD não há optimizações que possam ser feitas? Por exemplo criação de índices? Também vejo que a tua query inicial tem muitos “OR”. Normalmente para uma BD isso é sinónimo de maus planos de execução e longos tempos de processamento.

Legal cara, são muito validas suas observações. Eu agradeço.
Depois posto aqui o desenrolar da bagaça.