Usando hiberante de forma otimizada

Post on 21-Jun-2015

80 views 7 download

description

Usado Hibernate de forma otimizada

Transcript of Usando hiberante de forma otimizada

S

Usando Hibernate de Forma Otimizada

Jadson Santos

Hibernate Otimizado

S  Hibernate S  O Hibernate é um framework para o mapeamento objeto-

relacional escrito na linguagem Java. Este framework facilita o mapeamento dos atributos entre uma base tradicional de dados relacionais e o modelo objeto de uma aplicação, mediante o uso de arquivos XML ou anotações Java.

Hibernate Otimizado

S  A principal promessa do Hibernate S  Quando a gente começa a estudar o Hibernate, a principal

promessa para vender o produto é: O Hibernate gera as chamadas SQL e libera o desenvolvedor de trabalhar com os dados de forma relacional, desde que os mapeamentos das classes de domínio tenham sido realizados, o desenvolvedor irá trabalhar apenas com objetos

S  Então oba S  Eu tenho o id da entidade e para recuperar seus dados eu vou no

meu Dao que usa Hibernate e faço:

Entidade e = dao.findById(1);

S  E tenho o objeto “e” populado, simples!

Hibernate Otimizado

S  O problema é que essa promessa não é cumprida S  Na prática, apenas se for uma entidade de domínio com

poucos dados e sem relacionamento com outras entidades do sistema isso vai funcionar

public class TipoAluno{

@Id

private int id;

@Column(name = "descricao")

private String descricao; }

Hibernate Otimizado

S  Normalmente no seu sistema você terá apenas 10 ou 20 tipos de alunos e serão sempre recuperados apenas o id e a descrição

S  Para entidades que possuem dezenas de milhares de linhas na tabela para cima, e que possuam muitos relacionamentos essa abordagem deixar o seu sistema lendo e não escalável.

Hibernate Otimizado

public class Aluno{ @ManyToOne

@JoinColumn(name = "id_tipo_aluno")

private TipoAluno tipo;

@ManyToOne(fetch = FetchType.EAGER)

@JoinColumn(name ="id_discipina”)

private Disciplina discipinas; }

Hibernate Otimizado

S  O que vai ocorrer se você for usar “orientação a objetos” e fizer um findById na entidade Aluno?

S  O Hibernate vai recuperar todas as informações do Aluno, +todas as informações dos tipo de alunos + todas as informações das disciplinas associadas ao aluno + todas as informações das entidades associadas a disciplinas e assim sucessivamente, até o nível máximo definido nas configurações do Hibernate

S  Multiplique por 1000 usuários fazendo essa consulta. Já viu o problema ne?

Hibernate Otimizado

S  Já sei! Troco o mapeamento de EAGER para LAZY.

S  Resolve em parte, o Hibernate não irá trazer os dados dos relacionamentos, porém a cada vez que você fizer aluno.getDisciplinas() com a sessão aberta ele gerará N consultas extras para recuperar as disciplinas. Onde N é o número de disciplinas no aluno.

S  Se no sistema existem 1000 alunos consultando suas disciplinas e, em média, cada aluno está matriculado em 5 disciplinas, em vez de 1.000 consultas banco, o Hibernate gerará 1.000 iniciais + 5.000 consultas para recuperar informações da disciplinas

Hibernate Otimizado

S  Se a sessão do Hiberante já estiver fechada, você passará por um problema bastante conhecido de LazyInitializationException. E um erro será gerado para o usuário

Hibernate Otimizado

S  Então como eu resolvo isso?

S  Simples! Mapeie tudo o LAZY, faça projeção das suas consultas, recupere apenas os dados necessários e popule o seu objeto.

SELECT aluno.id, aluno.nome, tipo.descricao

FROM Aluno aluno

INNER JOIN aluno.tipo tipo

WHERE aluno.id = :idAluno

Hibernate Otimizado

S  Essa consulta irá retornar uma lista de arrays de objetos

List<Object[]> dados= q.list();

S  Existem alguns métodos utilitário que podem ser usado para popular os objetos a partir a lista retorna pela consulta

Hibernate Otimizado

S Isso resolverá 90% dos problemas de performance do seu sistema

S Mas é muito trabalho? Eu sei! mas você quer qualidade no seu sistema ou não?

Hibernate Otimizado

S  Quando eu falo em adicionar projeção são significa fazer isso:

SELECT aluno.*

FROM Aluno aluno

WHERE aluno.id = :idAluno

S  Isso não é fazer projeção!

Hibernate Otimizado

S  E os outros 10% ? S  Esses 10% entram os caos de uso que são muitos usado ou

casos de uso onde o requisito de performance é fundamental

S  Nestes casos você deve utilizar diretamente SQL e tem que “escovar os bits” da sua consulta SQL para ver como ela pode ser otimizada

S  O Hibernate nesses casos dá nem pro gasto.

Hibernate Otimizado

S  Como eu sei o que otimizar?

S  Por exemplo, no PostgreSQL existe uma opção chamada “Explain Query" que mostra como o banco está realizando a sua consulta

S  No exemplo a seguir a consulta SQL deveria retorna os 20 primeiros resultados de um JOIN entre duas tabelas

Hibernate Otimizado

SELECT s.id_servidor, p.id_pessoa

FROM rh.servidor

JOIN JOIN comum.pessoa p ON....

WHERE .....

LIMIT 20

Hibernate Otimizado

S  Apesar da quantidade de dados retornado ser pequena, o limite só pode ser aplicado depois que as condições do JOIN foram testadas, então o Banco de dados irá realizar o Seq Scan em todas as tabelas para realizar o JOIN.

S  Seq Scan em tabelas grandes sempre é um problema

S  Isso quer dizer que ele precisa percorrer varias tabelas com milhares de resultados para realizar a consulta. O que demora em média 500ms.

S  Super rápido, mas pense que 100 usuários podem estar utilizando essa consulta, então são 50 segundos em produção de uso do banco de dados.

Hibernate Otimizado

Hibernate Otimizado

S  Como eu só quero um conjunto pequeno de dados, a saída foi realizar uma sub consulta menor antes, que restringisse o meu conjunto de resultados antes de realizar o JOINs da consulta principal

Hibernate Otimizado SELECT s.id_servidor, p.id_pessoa

FROM rh.servidor

JOIN JOIN comum.pessoa p ON....

WHERE s.id_servidor IN ( -------------------------------------------------

--- Otimização, só recupera desse conjunto pequeno de dados ---

SELECT s.id_servidor FROM ... WHERE ...

LIMIT 100

-------------------------------------------------

)

LIMIT 20

Hibernate Otimizado

S  Isso fez o tempo da consulta cair de 500ms para 17ms. Que para 100 usuários o tempo total de uso do banco cai de 50 segundos para 1,7segudos.

Hibernate Otimizado

S  Outro exemplo de otimização de consultas SQLs

S  Tenho um problema onde se deveria verificar se um usuário estava entre os resultados retornados por uma determina consulta.

S  Como isso foi realizado a princípio?

Hibernate Otimizado

SELECT count(id_pessoa)

FROM comum.pessoa p

WHERE 123456 – id da pessoa a ser testado

IN(

--- consulta interna

select p.id_pessoa FROM ....

)

Hibernate Otimizado

S  Porém essa consulta interna pode retornar um número muito grande dados, na ordem de 2.000.000 de ids para verificar se o usuário que você quer, está dentro desse conjunto

S  Resultado: 1 segundo a consulta x 100 usuários : 100 segundos de uso do banco.

S  Será que não existe uma maneira mais otimizada de fazer isso?

Hibernate Otimizado

S  Se você parar para pensar um pouco, verá que se eu quero verificar se um determinado usuário está no grupo da consulta é só verificar se:

( count(*) consulta AND meu usuário ) > 0

Hibernate Otimizado

SELECT count(interna.id_pessoa)

FROM (

-- consulta anterior

select p.id_pessoa

FROM comum.pessoa p

INNER JOIN ....

-- e meu usuário

AND p.id_pessoa = 123456

) as interna

Hibernate Otimizado

S  Resultado: De 1 segundo o tempo da consulta caiu para 17ms , para 100 usuários : 1,7 segundos de uso do banco.

+- 5.800 % de ganho do tempo da consulta. Só isso. É pouco?

Hibernate Otimizado

S  Conclusões S  O Hibernate se tornou o framework padrão para

mapeamento objeto relacional, porém o seu mau uso trás sérios problemas de performance ao sistema.

S  O mapeamento dos relacionamentos do domínio como LAZY e a recuperação apenas das informações necessárias ao seu caso de uso resolve 90% das questões de performance do seu sistema

S  Os demais 10%, onde o requisito de performance é fundamental, deve abandonar o Hibernate e analisar os pontos mais demorados da sua consulta e tentar descobrir maneiras de otimizá-la

S  Esses 10% vai muito da experiência e habilidade do desenvolvedor

Hibernate Otimizado

S  Conclusões S  Falei apenas das otimizações em relação ao tempo das

consultas, existe ainda outras maneiras de otimizar consultas como criar cache em memória ou desnormalização das tabelas do banco de dados. Ou ainda, em casos específicos, o uso de banco de dados não relacionais.

S

Usando Hibernate de Forma Otimizada

Jadson Santos