[RESOLVIDO] Select muito lento com Hibernate + JPA + Postgres

Olá amigos!

Estou criando uma aplicação web comercial e possuo uma tabela de Ceps com pouco mais de 705mil registros que tem um relacionamento de N para 1 com Cidades que por sua vez tem um relacionamento N para 1 com Estados. No momento estou usando MySQL como base de dados. Quando o usuário digita o cep, o programa busca o cep dentre esses 705mil e retorna a cidade e o estado. Com o MySQL, quando digito o cep e é executado o select, o Hibernate/JPA demora em torno de 4 a 5 segundos para retornar a cidade e o estado. Resolvi fazer um teste migrando as tabelas de Ceps, Cidades e Estados para o Postgres e fiz um teste direto no executando o select abaixo:

select * from ceps cep inner join cidades cidade on (cep.id_cidade = cidade.cd_cidade) where cep.numero_cep = '86390000';

Primeiro testei no Workbench do MySQL, a consulta levou em torno de 3 a 4 segundos para retornar o registro, no pgAdmin do Postgres, o retorno foi em torno de de 1 a 2 segundos. Resolvi testar na minha aplicação, e para minha surpresa, quando digitava o cep e iniciava a busca, o Hibernate/JPA demorava muito tempo para retornar, mais de 30 segundos, em quanto que com o MySQL demorava quase o mesmo tempo de quando consultado direto no banco. Olhando o console do Tomcat, vi que o hibernate gera muitos selects, até retornar o dado, com o MySQL ele gera, porém é muito mais rápido.

Então gostaria de saber, isso é normal? Principalmente esses vários selects que o hibernate cria? Alguém tem alguma experiência parecida com essa?

O Dao que faz a pesquisa é esse:

        public Ceps getCepPorNumero(Integer numero) throws Exception {
		manager = Conexao.getFactory().createEntityManager();
		try {
			manager.getTransaction().begin();
			TypedQuery<Ceps> query = manager.createQuery("select c from Ceps c where c.numeroCep = :numero", Ceps.class);
			query.setParameter("numero", numero);
			Ceps c = query.getSingleResult();
			manager.getTransaction().commit();
			return c;
		} finally {
			manager.close();
		}
	}

Meu modelo Ceps:

import java.io.Serializable;

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

@Entity
@Table(name="ceps")
public class Ceps implements Serializable {

	@Id
	@GeneratedValue
	private Long id;
	
	@ManyToOne
	@JoinColumn(name="id_cidade")
	private Cidades cidade;
	
	@Column(name="numero_cep")
	private Integer numeroCep;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Cidades getCidade() {
		return cidade;
	}

	public void setCidade(Cidades cidade) {
		this.cidade = cidade;
	}

	public Integer getNumeroCep() {
		return numeroCep;
	}

	public void setNumeroCep(Integer numeroCep) {
		this.numeroCep = numeroCep;
	}
	
	
}

Abraços.

  1. @ManyToOne Cidades => Note que ele irá carregar a cidade junto. Cidade tem mais o que EAGER? Esse deve ser o seu gargalo (aqui explica melhor o conceito de EAGER/LAZY nos relacionamentos JPA: Mini Livro - Primeiros passos e conceitos detalhados).
  2. Para consulta como você está fazendo, nem precisa abrir/fechar transação. Pegue um entityManager e faça a consulta sem abrir a transação, pois isso afeta na performance por causa de attached/detached e tals (aqui explica melhor isso: JPA Consultas e Dicas).

Valeu Hebert!!

Foi uma mancada minha. Em Ceps eu tinha esse @ManyToOne para Cidades, e em Cidades eu tinha um @OneToMany para Ceps. Retirei o relacionamento no modelo Cidades e a consulta foi no ato.

Muito obrigado cara!

Já estou dando uma olhada nos links! Muito bom o conteúdo que estou vendo até aqui.

[quote=nazgulzurak]Já estou dando uma olhada nos links! Muito bom o conteúdo que estou vendo até aqui.[/quote]Opa! Maravilha. [=