Pregunta

Estoy usando la implementación de Jibernate de JPA y estoy viendo un bajo rendimiento ya que se emiten múltiples consultas SQL para cada entidad que se busca. Si utilizo una consulta JPA unida, genera solo una consulta SQL pero no encuentra filas con relación nula.

Ejemplo, considera este simple esquema. Una persona vive en una dirección y está empleada por una empresa. Tanto la dirección como el empleador son opcionales y, por lo tanto, pueden ser nulos.

@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 ...
}

No se muestra arriba es que cada entidad JPA tiene algún tipo de ID (clave):

@Id
public Integer id;

El problema que estoy viendo es que una sola consulta JPA en persona produce múltiples consultas SQL en la base de datos. Por ejemplo, la siguiente consulta JPA:

select p from Person p where ...

da como resultado la consulta SQL:

select ... from Person where ...

y también el siguiente par de consultas SQL para cada persona recuperada:

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

Esto tiene un gran impacto en el rendimiento. Si el conjunto de resultados de la consulta es 1000 personas, genera 1 + 1000 + 1000 = 2001 consultas SQL.

Así que intenté optimizar la consulta JPA forzándola a unirse:

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

o:

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

Esto da como resultado una única consulta SQL con un montón de combinaciones. El problema es que si la dirección o el empleador son nulos, entonces la consulta unida no la encontrará.

Así que me quedo con el uso de la consulta sin unión que es lenta, o la consulta rápida que no recupera filas anulará las relaciones. Debo estar perdiendo algo aquí. Seguramente hay una manera de realizar consultas rápidas y completas.

¿Fue útil?

Solución

Supongo que necesitarías una unión izquierda, es decir,

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

Consulte esta entrada de blog para un ejemplo

Tenga en cuenta que en realidad no lo he intentado con JPA, pero funciona bien en HQL, que es la base para el estándar JPA de muchas maneras.

La razón por la que no funciona con uniones simples es que el valor predeterminado es una unión interna.

Otros consejos

Intente establecer un tamaño de lote (@BatchSize) en las entidades de Dirección y Compañía. No los cargará en una combinación (¿es eso lo que buscas?), Pero cargará un montón de ellos cada vez que se cargue uno. El tamaño de lote indica cuántos debería cargar cuando descubre que necesita uno.

Si tiene un lote de 1 (el valor predeterminado), y carga 10 personas. Luego, realice una iteración sobre ellos, lea su dirección y los elementos de la compañía, luego hibernación hará una consulta para las 10 personas, luego, cada vez que necesite la dirección o la compañía para una de esas personas, hará una consulta para la dirección de esa persona.

Si ha configurado un tamaño de lote de 7 en la entidad de Dirección, cuando lea la primera dirección, verá que hay más de 7 Direcciones que están actualmente en proxy, e irán a buscarle 7 de las direcciones.

Si tiene una dirección y una compañía con un tamaño de lote de 7 y está iterando a través de 10 personas, esto resultará en 5 consultas, en lugar de las 21 que obtendría en este momento. Aún no es el 1 que una unión te dará. Sin embargo, la unión sería más lenta en los casos en los que solo desea que la Persona se oponga y no toque la Dirección / Entidad de la compañía incrustada en ellos (suponga que solo desea obtener una lista de los identificadores de la persona o cuente cuántos son hombres / mujeres)

Echa un vistazo a: http://hibernate.org/hib_docs/v3/reference/en/ html / performance.html

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top