Как мы можем проверить на проблему N + 1 в JPA / Hibernate? - PullRequest
1 голос
/ 26 апреля 2019

У меня проблема с N + 1, и я хотел бы написать какой-нибудь автоматический регрессионный тест, потому что он очень сильно влияет на производительность.

Я думал о шпионаже EntityManager и проверке, что его метод createQuery() вызывается только один раз, но Hibernate не использует его для инициализации ленивых отношений, поэтому он не работает. Я также мог бы попытаться закрыть транзакцию JPA между моим хранилищем и моим сервисом (или отсоединить мою сущность) и посмотреть на исключения, но это действительно ужасная идея.

Чтобы дать нам рамку, допустим, у нас есть очень простая модель родитель-потомок:

@Entity
public class Parent {
    …
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
    private Collection<Child> children;
}

@Entity
public class Child {
    …
    @ManyToOne
    private Parent parent;
}

И очень простой сервис:

public class MyService {
    …
    public void doSomething(Long parentId) {
        Parent parent = …; /* retrieve Parent from the database */
        doSomeOtherThing(parent.getChildren());
    }
}

Для родительского поиска из базы данных могут использоваться два следующих запроса:

SELECT parent FROM Parent parent WHERE parent.id = :id;
SELECT parent FROM Parent parent JOIN FETCH parent.children WHERE parent.id = :id;

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

Ответы [ 3 ]

0 голосов
/ 26 апреля 2019

См. Следующее решение, которое основано на упаковке DataSource. https://vladmihalcea.com/how-to-detect-the-n-plus-one-query-problem-during-testing/

0 голосов
/ 27 апреля 2019

Полагаю, под «регрессионным тестом» вы подразумеваете реальный тест, который, вероятно, запущен JUnit.

Общий способ обработки этого в модульном тесте может быть следующим:

  • configurehibernate.show_sql в true
  • перехватывать сообщения журнала, как описано в перехват .
  • сканирование файла журнала для
    • конкретных запросов, которые вы хотитеследует избегать
    • количество похожих запросов
0 голосов
/ 26 апреля 2019

В качестве опции вы можете проверить количество запросов (выборка, обновления, вставки) в тесте

 repository.findById(10L);

 SessionFactory sf = em.getEntityManagerFactory().unwrap(SessionFactory.class);
 Statistics statistics = sf.getStatistics();

 assertEquals(2L, statistics.getQueryExecutionCount());

См. Статистика гибернации

...