Pergunta

Eu estou usando implementação de JPA do Hibernate e estou vendo o mau desempenho como várias consultas SQL são emitidos para cada entidade que seja obtido. Se eu usar uma consulta JPA juntou ele gera apenas uma consulta SQL, mas não encontra linhas serão nulo relacionamento.

Exemplo, considere esse esquema simples. Uma pessoa vive em um endereço e é empregado por uma empresa. Ambos endereço e empregador são opcionais e podem, assim, ser nulo.

@Entity
public  class Person {
    public name;

    @ManyToOne
    @Column(nullable=true)
    public Address address

    @ManyToOne
    @Column(nullable=true)
    public Company employer
}

@Entity
public  class Address {
    address attributes ...
}

@Entity
public  class Company {
    company attributes ...
}

Não mostrado acima é que cada entidade JPA tem algum tipo de ID (chave):

@Id
public Integer id;

O problema que eu estou vendo é que uma única consulta JPA em Pessoa resulta em várias consultas SQL no banco de dados. Por exemplo, a seguinte consulta JPA:

select p from Person p where ...

resultados na consulta SQL:

select ... from Person where ...

e também o seguinte par de consultas SQL para cada pessoa recuperadas:

select ... from Address a where a.id=xxx
select ... from Company c where c.id=yyy

Isto tem um enorme impacto sobre o desempenho. Se o conjunto de resultados da consulta é de 1000 pessoas, então ele gera 1 + 1000 + 1000 = 2001 consultas SQL.

Então, eu tentei otimizar a consulta JPA, forçando-o a juntar-se:

select p from Person p join p.address a join p.employer e where ...

ou

select p, a, e from Person p join p.address a join p.employer e where ...

Isso resulta em uma consulta SQL única com um grupo de junta. O problema é se o endereço ou o empregador é nulo, então a consulta juntou não vai encontrá-lo.

Então, eu estou à esquerda com qualquer um usando a juntar-less consulta que é lento, ou a consulta rápida juntou que não recuperar linhas será nula relacionamentos. Eu devo estar esquecendo algo aqui. Certamente há uma maneira para consulta rápida e completa.

Foi útil?

Solução

Meu palpite é que você precisará de uma associação à esquerda, ou seja.,

SELECT p FROM Person p LEFT JOIN p.address a LEFT JOIN p.employer e WHERE...

Veja esta entrada do blog para um exemplo

Note que eu não tenha realmente tentei isso com JPA, mas ele funciona bem em HQL, que é a base para o padrão JPA de muitas maneiras.

A razão não está trabalhando com plain juntar-se de é que o padrão é uma junção interna.

Outras dicas

Tente configurar um batchsize (@BatchSize) sobre as entidades endereço e Companhia. Não vai carregá-los em uma join (é isso que você está depois?), Mas ele vai carregar um monte deles cada um o tempo está carregado. O batchsize diz quantos ele deve carregar quando ele descobre que ele precisa de um.

Se você tem um batchsize de 1 (o padrão), e carga de 10 pessoas. Em seguida, iterar sobre eles, lendo os seus itens de endereço e de empresas, então o Hibernate irá fazer uma consulta para as 10 pessoas, em seguida, cada vez que precisa do endereço ou empresa para uma dessas pessoas, então ele irá fazer uma consulta para o endereço dessa pessoa.

Se você tiver definido uma batchsize de 7 na entidade Endereço então, quando você lê o primeiro endereço, vai ver que há mais de 7 endereços que são actualmente aproximados, e vai e te 7 dos endereços.

Se você tem tanto Endereço and Company com um BatchSize de 7 e você é a iteração através de 10 pessoas, então isso irá resultar em 5 consultas, ao invés do 21 yo iria receber no momento. Ainda não é o 1 que uma junção Wold dar-lhe. No entanto, a junção seria mais lenta nos casos em que você só quer que a pessoa objetos e não vai estar tocando as entidades Address / Empresa embutidos nelas (digamos que você quer apenas para obter uma lista das pessoas ids, ou contar quantas são do sexo masculino / feminino)

Tenha um olhar em: http://hibernate.org/hib_docs/v3/reference/en/ html / performance.html

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top