[RESOLVIDO]Hibernate + MySQL: Problema de performance

Boa tarde galera,
estou com uma duvida meio cabreira aqui.

Tenho uma tabela no banco, que possui cerca de 35mil registros.
Quando eu peço pra fazer um select em TODOS os dados dessa tabela

Session session = getSession();
Query query = session.createQuery("from Ocorrencia");
List<Ocorrencia> listaOcorrencias = new ArrayList<Ocorrencia>();
listaOcorrencias = query.list();
session.close();
System.out.println(listaOcorrencias.size());

a aplicaçao demora cerca de 15 segundos pra me retornar esse resultado.
É um tempo bem grande ao meu ver, mas, um problema de cada vez.

Para entender o meu problema, devemos entender o que eu quero.
Tenho uma tabela Demanda, que pode possuir várias Ocorrencias, cada uma.
Sendo assim, eu quero que essa consulta, me traga todas as ultimas Ocorrencias de cada Demanda do banco.
Minha query ficou assim:

Session session = getSession();
Query query = session.createQuery("from Ocorrencia o where o.data in(select max(oc.data) from Ocorrencia oc group by oc.demanda.idDemanda)");
List<Ocorrencia> listaOcorrencias = new ArrayList<Ocorrencia>();
listaOcorrencias = query.list();
session.close();
System.out.println(listaOcorrencias.size());

Quando faço isso, ele nao me retorna resposta alguma, fica carregando eternamente.
Esperei cerca de 5 minutos pela resposta, e ela nao veio.

Fico me perguntando se a consulta travou por algum motivo, ou se ela ainda estava sendo feita…eternamente.

Será que alguem tem alguma dica de como melhorar e concertar isso ai?

Estou no aguardo!

Mostra o mapeamento.
Você não colocou como @Eager não né ?

Ih caraca! Tenho 5 objetos definidos como EAGER.
Com certeza é isso!

Hahahahaha!!!

Vou verificar aqui e passo um feedback!

Dá uma olhada por conta que se são 5 mil registros imagina os filhos de cada um deles.

Talvez isso esteja causando o gargalo dos 15 segundos.

Só cuidado após trocar para lazy com lazy inicialization exception

Então, fiz o teste, e na consulta geralzona (from Ocorrencia), reduziu o tempo de 15 pra 3 segundos.

O que pra mim já é aceitável.

Porém, o problema da query utilizando a clausula “IN”, permanece. Fica um bom tempo e nao tenho resposta.

Seguem meus mapeamentos.

Ocorrencia:


package br.com.jm.beans;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name="ocorrencia")
public class Ocorrencia implements Serializable{
	private static final long serialVersionUID = -2051090227918002023L;
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="id_ocorrencia")
	private Integer idOcorrencia;
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="id_usuario")
	private Usuario usuario;
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="id_demanda")
	private Demanda demanda;
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="id_responsavel")
	private Usuario responsavel = new Usuario();
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="id_setor")
	private Setor setor;
	@Column(name="oc_data")
	private Date data;
	@Column(name="oc_acao")
	private String acao;
	@Column(name="oc_desc")
	private String descricao;
	@Column(name="oc_solic")
	private String solicitacao;
	@Transient
	private Integer index;
	@Transient
	private String ac;
	@Transient
	private String sdata;

        // GETTERS E SETTERS
}

Demandas:


package br.com.jm.beans;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name="demanda")
public class Demanda implements Serializable{
	private static final long serialVersionUID = 4959562413119839409L;
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="id_demanda")
	private Integer idDemanda;
	@ManyToOne(fetch=FetchType.EAGER)
	@JoinColumn(name="id_eleitor", nullable=true)
	private Eleitor eleitor;
	@Column(name="dm_solic")
	private String solic;
	@Column(name="dm_desc")
	private String desc;
	@Column(name="dm_status")
	private String status;
	@Column(name="dm_local")
	private String local;
	@OneToMany(mappedBy="demanda", fetch=FetchType.EAGER, cascade={CascadeType.DETACH,CascadeType.REMOVE})
	private List<Ocorrencia> listaOcorrencias;
	@Transient
	private SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
	@Transient
	private Date periodoIni;
	@Transient
	private Date periodoFin;
	@Transient
	private String nsolic;
	@Transient
	private String nlocal;
	
	public Demanda(){
		
	}
	
	public Demanda(String solic){
		this.solic = solic;
	}
	
        //GETTERS E SETTERS
}

Chegou a debugar e viu que não saía do

Query query = session.createQuery(“from Ocorrencia o where o.data in(select max(oc.data) from Ocorrencia oc group by oc.demanda.idDemanda)”); ?

Não dá para trocar o in por um

Query query = session.createQuery(“from Ocorrencia o where o.data = (select max(oc.data) from Ocorrencia oc group by oc.demanda.idDemanda)”);

Afinal o in só está filtrando um cara mesmo.

Debuguei sim, e ele trava quando ativa o list().

O negocio do = é que ele retorna mais de 1 resultado no subselect, por causa do group by.

Não dá para colocar um distinct não ?

Por sinal precisa de subselect ?
Não dá para fazer assim não ?

Query query = session.createQuery(“select distinct from Ocorrencia o where o.data = max(o.data) group by o.demanda.idDemanda)”);

Tentei dessa forma e ele me retornou um “invalid use of group function”

Tentei tirar a clausula group by, mas ele continuou dando o mesmo erro. Oo

O erro é porque você está usando o max em um where.

Pode tentar isso aqui

Volta com o subselect mesmo.

Query query = session.createQuery(“select distinct o from Ocorrencia o where o.data = (select max(oc.data) from Ocorrencia oc )”);

Por enquanto deixa sem o groupBy mesmo.

Dessa vez ele me retornou 2 resultados…

Deveria retornar bem mais…Oo

Me explica o que você quer nessa consulta por favor

É estranho porque eu usava exatamente aquela primeira query, quando meu banco estava populado com dados fictícios.

Acho que existiam cerca de 30 Ocorrencias e 10 Demandas. Ele me retornava tudo certinho.

Porém, quando migrei o banco real, e passou a ter 35mil registros…ele começou a dar esse problema.

É o seguinte:

Tenho essa tabela de Ocorrencias, cada ocorrencia pertence ä uma demanda. À medida que uma demanda vai ganhando avanços, novas ocorrencias vão sendo
cadastradas…juntando assim varias ocorrencias filhas de uma demanda.

Quando o usuario loga no sistema, ele tem uma caixa de entrada de demandas que ele tem que resolver. Nessa caixa de entrada, eu quero que seja mostrado
os dados da ultima ocorrencia, de cada demanda que esteja sob responsabilidade desse usuario.

Ou seja, quero retornar a ultima ocorrencia, de cada demanda do sistema. Isso eu verifico pela data, pego a maior data de cada ocorrencia, e armazeno essa ocorrencia, que representa uma demanda.
E por ai vai…até montar a caixa de entrada do usuario.

Não sei se ficou confuso de entender…

O que você quer trazer ?

Porque o max(o.data) ?

Como é que você vai saber que a data da última demanda de uma ocorrência, pois pelo modelo as demandas tem 2 datas ?

E a data da ocorrência é a data que ela foi aberta ?
Ou a data da ocorrência é atualizada

Então, eu so utilizo uma data nessa consulta, que é a data do objeto Ocorrencia.
Essa data é a data de cada acontecimento que se segue no decorrer daquela demanda.
Cada acontecimento é uma Ocorrencia.

As datas que voce identificou, são do objeto Demanda, essas datas não sao utilizadas nessa consulta,
somente em consulta para encontrar Demandas que foram iniciadas em um periodo de tempo.

Tá complicado essa consulta hein.rsrs
Não sei se isso que coloquei vai funcionar.

Query query = session.createQuery(“select d from demanda d where d.ocorrencia = (select oc,max(oc.data) as maior from Ocorrencia oc join demanda d where oc.data = maior)”);

Tentei trazer uma lista de demandas, em que cada demanda teria a maior ocorrência

Qualquer coisa coloca a dúvida lá no forum de sql e depois traduz para o hibernate.

Vamos imaginar uma situação:

Um chefe enviou uma demanda pro seu funcionario, nessa demanda ele disse que queria que fosse contratada uma fornecedora de café pra repartição.

Com isso, foi gerada uma Demanda.

Quando esse funcionario logar no sistema, ele vai notar na caixa de entrada dele essa demanda. Então ele vai enviar essa demanda pro setor de contatos,
pois ele já pesquisou qual a fornecedora mais em conta, e quer que o pessoal de contato, entre em contato com a empresa pra fechar negocio. Com isso
foi gerada outra Ocorrencia na mesma demanda.

Quando o usuario do setor de contatos logar, ele vai notar na caixa dele essa nova Ocorrencia. Ele vai entrar em contato com a fornecedora, e vai devolver
essa demanda para o funcionario inicial, criando assim outra Ocorrencia.

Finalmente, o usuario vai ver que o contrato foi fechado, e vai finalizar a demanda, definindo seu status como “FINALIZADO”.

Moral da historia: quando o usuario do setor de contatos entrou no sistema, ele so queria ver na caixa de entrada dele, os dados referentes ä ultima ocorrencia
daquela demanda que foi encaminhada para ele. Daí vem a necessidade do max(o.data).