Оптимизация запросов JPA / Hibernate с нулевыми значениями

StackOverflow https://stackoverflow.com/questions/408456

Вопрос

Я использую реализацию JPA от Hibernate и наблюдаю низкую производительность, поскольку для каждого извлекаемого объекта выдается несколько SQL-запросов.Если я использую объединенный запрос JPA, он генерирует только один SQL-запрос, но не находит отношения rows will null.

Например, рассмотрим эту простую схему.Человек живет по определенному адресу и работает в компании.Как адрес, так и работодатель являются необязательными и, таким образом, могут быть нулевыми.

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

Выше не показано, что каждый объект JPA имеет какой-то идентификатор (ключ):

@Id
public Integer id;

Проблема, которую я вижу, заключается в том, что один JPA-запрос к Person приводит к нескольким SQL-запросам к базе данных.Например, следующий запрос JPA:

select p from Person p where ...

результаты в SQL-запросе:

select ... from Person where ...

а также следующая пара SQL-запросов для каждый возвращенный человек:

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

Это оказывает огромное влияние на производительность.Если результирующий набор запроса равен 1000 людям, то он генерирует 1+1000+1000 =2001 SQL-запросов.

Поэтому я попытался оптимизировать запрос JPA, принудительно присоединив его к join:

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

или:

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

Это приводит к одному-единственному SQL-запросу с кучей объединений.Проблема в том, что если address или employer имеет значение null, то объединенный запрос его не найдет.

Таким образом, мне остается либо использовать запрос без объединения, который является медленным, либо запрос с быстрым соединением, который не извлекает строки, приведет к обнулению связей.Должно быть, я здесь чего-то не понимаю.Конечно, есть способ для быстрого и полного выполнения запросов.

Это было полезно?

Решение

Я предполагаю, что вам понадобится левое соединение, т.е.,

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

Видишь эта запись в блоге для примера

Обратите внимание, что на самом деле я не пробовал это с JPA, но это прекрасно работает в HQL, который во многих отношениях является основой для стандарта JPA.

Причина, по которой это не работает с обычными соединениями, заключается в том, что по умолчанию используется внутреннее соединение.

Другие советы

Попробуйте установить размер пакета (@BatchSize) для адресов и компаний.Он не будет загружать их в join (это то, что вам нужно?), но он будет загружать их несколько при каждой загрузке.Размер пакета указывает, сколько его следует загрузить, когда он обнаружит, что ему это нужно.

Если у вас размер пакета равен 1 (по умолчанию), и загружается 10 человек.Затем выполните итерацию по ним, считывая их адреса и элементы компании, затем hibernate выполнит один запрос для 10 человек, затем каждый раз, когда ему понадобится адрес или компания для одного из этих людей, он будет запрашивать адрес этого человека.

Если вы установили размер пакета 7 для объекта Address, то, когда вы прочитаете первый адрес, он увидит, что в данный момент проксировано более 7 адресов, и перейдет и получит вам 7 адресов.

Если у вас есть и адрес, и Компания с размером пакета 7, и вы перебираете 10 человек, то это приведет к 5 запросам, а не к 21, которые вы получили бы на данный момент.Все еще не тот номер 1, который вам даст join wold.Однако объединение будет происходить медленнее в случаях, когда вам просто нужны объекты Person и вы не собираетесь касаться объектов Address / Company, встроенных в них (скажем, вы просто хотите получить список идентификаторов person или подсчитать, сколько из них мужского / женского пола)

Взгляните на:http://hibernate.org/hib_docs/v3/reference/en/html/performance.html

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top