Hibernate e Desempenho

5 respostas
PePeLeGaL

Boa noite meu povo,

Quero levantar uma questao que já foi discutida em partes aqui no forum.

Hibernate é bom do ponto de vista do programador, pois em geral facilita a vida do programador. Por outro lado, do ponto de vista do usuario final, isso nao tem o menor sentido, porque usuario final nao ve codigo. Usuario final quer simplesmente que o programa execute as funcoes que ele deseja. Para ele nao importa em qual linguagem foi feita.

Fiz essa colocacao porque tenho um amigo que é arquiteto e ele trabalha em uma empresa de grande porte. Ele disse que o sistema lá em que eles utilizaram hibernate está todo sendo alterado para sql puro, porque aumentaria o desempenho fazendo as alteracoes.

Entao, hibernate é bom apenas para o programador? Em que ele é bom para o usuario final, que nem ve codigo?

Obrigado,

5 Respostas

remixlara

Cara, por traz o hibernate utiliza SQL. O Hibernate é apenas um framework de persistência, ou seja, ele alinha seu código ao seu banco de dados…
a unica coisa que ele faz é gerenciar seu banco de dados através de classes e anotações…
agora o mau uso do hibernate pode realmente causar este problema… é preciso gerenciar bem todos os recursos disponíveis pelo hibernate…
um bom estudo poderia automatizar muito um trabalho árduo e desnecessário de gerenciar consultas sql’s.
É o que eu penso… utilizei hibernate em um sistema de grande porte e ele se comportou normalmente…
vlw, abs

partenon

Vamos por partes :slight_smile: JDBC puro significa fazer ORM na mao. Ou seja, mapear classes Java para tabelas no banco de dados. Este eh o problema basico que o Hibernate resolve, entao, eu diria que em 99% das vezes a troca do Hibernate para “JDBC puro” por questoes de performance eh totalmente sem fundamento. Como “diversao”, olhe esta pagina e veja qual eh o custo estimado do “Hibernate”: http://www.ohloh.net/p/hibernate : $ 14,304,021 . Isso significa que se o Hibernate fosse desenvolvido dentro de uma empresa, ele custaria isso.

Implementar JDBC na mao, significa que vc tem que resolver estes problemas (que ja foram resolvidos pelo Hibernate):

  • O famoso problema N+1 (faco uma query que retorna muitos dados, ou vou diversas vezes ao banco de dados?). Em outras palavras, Lazy Loading.
  • Cache
  • Versionamento (e auditoria)
  • Quer usar outro banco de dados? Voce precisa de um esquema para abstrair, como os “Dialects”.
  • JDBC Batching.
  • Mapeamento de colecoes.
  • Custo de aprendizado para um novo desenvolvedor na equipe (usar um “padrao” significa que vc pode anunciar uma vaga pedindo JPA, e sabe que todos sabem como usar)
  • Testes. Ja olhou quantos testes existem no “test suite” do Hibernate?
  • Integracao com outros produtos (Seam, Spring, …)
  • Outras coisas que nem consigo pensar agora :slight_smile:

Se voce tem um problema de perfomance, eu diria com 90% de chances de acertar que o problema nao eh com o Hibernate. E mesmo que seja, voce pode sempre cair no “fall back” e rodar a query de forma manual (como Workers, talves). Ou ainda, pode implementar apenas a parte problematica usando JDBC direto.

Enfim, a decisao de se abrir mao do Hibernate (ou de qualquer outra implementacao JPA) tem que ser seguida de dados reais com testes reais de performance, onde se evidencia o problema no produto. E diria que se vc realmente achou um problema de performance, pode abrir um JIRA que alguem vai dar uma olhada (prometo!).

F

Olá pessoal,
me desculpem comentar um post antigo, mas estou enfrentando um problema de performance usando hibernate.
É muito provável que seja a falta de experiência com o framework.

Recursos da aplicação:
Hibernate, partes com Spring, e JSF e Primefaces, banco postgresql

Gostaria de citar meu problema:

Estou montando uma aplicação onde registro algumas entrevistas internas, então tenho dados do funcionário, entrevistador e das questões da entrevista.
De imediato percebe-se que podemos ter 3 tabelas, entretanto o funcionário e o entrevistador fazem parte da mesma tabela funcionário. Então temos 2 tabelas no banco - Funcionário, Entrevistas.

Só tem um detalhe, teremos ainda as tabelas de Datas Salariais, Cargo, Função e Área todas essas tabelas possuem relações com o funcionário.

Tenho uma página de consulta onde será listada todas as entrevistas, hoje temos 400 entrevistas como carga inicial e é nessa página de consulta que há problema de performance.
Eu uso nessa página um datatable. É exatamente o mesmo que está nas demonstrações do primefaces:
http://www.primefaces.org/showcase/ui/datatableComplex.jsf

Eu também adicionei um <p:ajax event=“rowSelect” />, pois as informações mais detalhadas será mostrada em um dialog. Por isso preciso de todos os dados.

Abaixo segue as classes que montei, sei que temos um recurso chamado LAZY e EAGER para consultas @OneToMany, estou usando EAGER pois terei todas as informações de uma só vez, se eu utilizasse o LAZY provavelmente durante a renderização dos dados ele faria todas as outras consultas do mesmo jeito.

Acessando pela internet levou ~1 minuto e 30 segundos para apresentar as 400 entrevistas, pense no usuário clicando no menu de consulta e a página fica ali carregando, eu mesmo não aguentei o tempo que está levando. Já usando a rede local levou ~10 segundos. Mas esses números (400 conforme mencionado acima) tendem a dobrar a cada 3 ou 4 meses.

Minhas questões:

1- Poderiam sugerir um forma melhor de performance ?
2- Quanto ao uso do LAZY, o básico dele eu sei como funciona, mas eu costumo fechar a conexão logo após a query usando session.getTransaction().commit(); e session.close(); então recebo um lazy initialization exception, mas não entendi direito como usar o Open Session in View.
3- Para essa aplicação, o hibernate realmente pode me ajudar, não é ?

Se ficou alguma dúvida na minha explicação é só comentar, desde já agradeço.

Montei as associações mais ou menos assim (possuem pequenas alterações das originais, pois ainda há outros relacionamento e mais colunas):

// FUNCIONARIO

@Service
@Entity
@Table
@SequenceGenerator(name = "pk_sequence_funcionario", sequenceName = "funcionario_id_seq")
public class Funcionario implements Serializable {

	private static final long serialVersionUID = 253282986994912255L;

	@Id
	@Column
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "pk_sequence_funcionario")
	private Integer id;

	@Column
	@OrderBy(clause = "nome")
	private String nome;

        @Column
	private String email;

        @OneToOne
	@JoinColumn(name = "id_cargo")
	private Cargo cargo;

	@OneToOne
	@JoinColumn(name = "id_area")
	private Area area;

	@OneToMany(mappedBy = "funcionario", targetEntity = Salario.class, fetch = FetchType.EAGER)
	@OrderBy(clause = "dataSalario")
	private List<Salario> listaSalarios;

	@OneToMany(mappedBy = "funcionario", targetEntity = Entrevista.class, fetch = FetchType.EAGER)
	@OrderBy(clause = "dataEntrevista ASC")
	private Set<Entrevista> listaEntrevista;

        //  temos ainda mais 4 colunas aqui, omiti para facilitar a leitura

        // getters setters
}
// SALARIO

@Service
@Entity
@Table
@SequenceGenerator(name = "pk_sequence_salario", sequenceName = "salario_id_seq")
public class Salario implements Serializable{

	private static final long serialVersionUID = -660215567623424277L;

	@Id
	@Column
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "pk_sequence_salario")
	private Integer id;
	
	@Column(name="data_entrada")
	private Date dataSalario;
	
	@ManyToOne
	@JoinColumn(name="id_funcionario")
	private Funcionario funcionario;

        // getters setters

}
// AREA

@Service
@Entity
@Table
@SequenceGenerator(name = "pk_sequence_area", sequenceName = "area_id_seq")
public class Area implements Serializable {

	private static final long serialVersionUID = -172491528235032442L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "pk_sequence_area")
	@Column
	private Integer id;

	@Column
	private String nome;

        // getters setters

}
// CARGO

@Service
@Entity
@Table
@SequenceGenerator(name = "pk_sequence_area", sequenceName = "area_id_seq")
public class Area implements Serializable {

	private static final long serialVersionUID = -172491528235032442L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "pk_sequence_area")
	@Column
	private Integer id;

	@Column
	private String nome;

        // getters setters

}
// ENTREVISTA

@Service
@Entity
@Table
@SequenceGenerator(name = "pk_sequence_entrevista", sequenceName = "entrevista_id_seq")
public class Entrevista implements Serializable {

	private static final long serialVersionUID = -4555908627091964524L;

	@Id
	@Column
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "pk_sequence_entrevista")
	private Integer id;

	@ManyToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "id_funcionario")
	private Funcionario funcionario;

	@ManyToOne
	@JoinColumn(name = "id_entrevistador")
	private Funcionario entrevistador;

	@Column(name = "data_entrevista")
	private Date dataEntrevista;

        @Column(name = "tecnologia_plataforma")
	private String tecnologiaPlataforma;

	@Column(name = "sistema_conhecimento")
	private String sistemaConhecidos;

	@Column(name = "dados_pessoais")
	private String dadosPessoais;

        // temos ainda mais 10 colunas aqui, omiti para facilitar a leitura

        // getters setters

}
javaflex

No geral sobre performance do Hibernate, consultas cabeludas sempre uso SQL nativo (named SQL). Consultas simples ou simples tendendo à média uso Criteria sobrescrevendo programaticamente os lazys para eager, além de fazer os joins, afim de gerar um único SQL para atender todas as informações que necessito para a consulta ou relatório específico.

Interessante para você ler: http://blog.caelum.com.br/os-7-habitos-dos-desenvolvedores-hibernate-e-jpa-altamente-eficazes/

F

Obrigado javaflex,

vou dar uma olhada no link.
Como precisei terminar logo a aplicação resolvi misturar hibernate com spring jdbc. Assim que sobrar um tempo pretendo voltar a realizar testes de performance (ou melhor estudar) e logo que possível eu volto perguntar ou até mesmo mostrar algum tipo de solução.

Abraços

Criado 26 de junho de 2010
Ultima resposta 19 de mai. de 2013
Respostas 5
Participantes 5