Оптимизация запросов JPA / Hibernate с нулевыми значениями - PullRequest
3 голосов
/ 03 января 2009

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

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

@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, заставив его присоединиться:

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-запрос с несколькими объединениями. Проблема в том, что если адрес или работодатель не заданы, объединенный запрос их не найдет.

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

Ответы [ 2 ]

3 голосов
/ 03 января 2009

Полагаю, вам нужно левое соединение, т.е.

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

См. эту запись в блоге для примера

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

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

0 голосов
/ 04 января 2009

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

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

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

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

Посмотрите на: http://hibernate.org/hib_docs/v3/reference/en/html/performance.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...