Рубрики
Без рубрики

Кэш плана запроса hibernate

Посмотрите, как кэш плана запросов Hibernate может помочь повысить производительность приложения.

Автор оригинала: baeldung.

1. Введение

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

2. Кэш плана запросов

Перед выполнением каждый запрос или запрос критериев JP’L анализируется на абстрактное синтаксисное дерево (AST), чтобы Hibernate можно было создать выписку из S’L. Поскольку компиляция запросов требует времени, Hibernate предоставляет ЗапросПланКаш для лучшей производительности.

Для родных запросов Hibernate извлекает информацию об названных параметрах и типе возврата запросов и хранит ее в ПараметрМе метаданные .

Для каждого выполнения Hibernate сначала проверяет кэш плана, и только если нет плана, он генерирует новый план и хранит план выполнения в кэше для будущей ссылки.

3. Конфигурация

Конфигурация кэша плана запроса контролируется следующими свойствами:

  • hibernate.query.plan_cache_max_size – контролирует максимальное количество записей в кэше плана (по умолчанию до 2048 года)
  • hibernate.query.plan_parameter_metadata_max_size – управляет числом ПараметрМе метаданные экземпляры в кэше (по умолчанию до 128)

Таким образом, если наше приложение выполняет больше запросов, чем размер кэша плана запроса, Hibernate придется потратить дополнительное время на компиляцию запросов. Таким образом, общее время выполнения запроса будет увеличиваться.

4. Настройка тестового корпуса

Как говорится в отрасли, когда дело доходит до производительности, никогда не доверяйте претензиям. Итак, Давайте проверьте, как меняется время компиляции запроса при изменении настроек кэша .

4.1. Классы сущностей, участвующие в тестировании

Начнем с того, что посмотрим на сущности, которые мы будем использовать в нашем примере, DeptEmployee и Департамент :

@Entity
public class DeptEmployee {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    private String employeeNumber;

    private String title;

    private String name;

    @ManyToOne
    private Department department;

   // standard getters and setters
}
@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    private String name;

    @OneToMany(mappedBy="department")
    private List employees;

    // standard getters and setters
}

4.2. Запросы в спячку, участвующие в тестировании

Для целей этой статьи мы будем использовать следующие три запроса:

  • findEmployeesByDepartmentИмя
session.createQuery("SELECT e FROM DeptEmployee e " +
  "JOIN e.department WHERE e.department.name = :deptName")
  .setMaxResults(30)
  .setHint(QueryHints.HINT_FETCH_SIZE, 30);
  • findEmployeesByDesignation
session.createQuery("SELECT e FROM DeptEmployee e " +
  "WHERE e.title = :designation")
  .setHint(QueryHints.SPEC_HINT_TIMEOUT, 1000);
  • findDepartmentOfAnEmployee
session.createQuery("SELECT e.department FROM DeptEmployee e " +
  "JOIN e.department WHERE e.employeeNumber = :empId");

5. Измерение воздействия на производительность

5.1. Настройка кода бенчмарка

Мы будем изменять размер кэша от одного до трех – после этого все три наших запроса уже будут в кэше. Поэтому нет смысла увеличивать его дальше:

@State(Scope.Thread)
public static class QueryPlanCacheBenchMarkState {
    @Param({"1", "2", "3"})
    public int planCacheSize;
    
    public Session session;

    @Setup
    public void stateSetup() throws IOException {
       session = initSession(planCacheSize);
    }

    private Session initSession(int planCacheSize) throws IOException {
        Properties properties = HibernateUtil.getProperties();
        properties.put("hibernate.query.plan_cache_max_size", planCacheSize);
        properties.put("hibernate.query.plan_parameter_metadata_max_size", planCacheSize);
        SessionFactory sessionFactory = HibernateUtil.getSessionFactoryByProperties(properties);
        return sessionFactory.openSession();
    }
    //teardown...
}

5.2. Код, который тестируемый

Далее давайте посмотрим на базовый код, используемый для измерения среднего времени, затытеваемого Hibernate при составлении запросов:

@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(1)
@Warmup(iterations = 2)
@Measurement(iterations = 5)
public void givenQueryPlanCacheSize_thenCompileQueries(
  QueryPlanCacheBenchMarkState state, Blackhole blackhole) {

    Query query1 = findEmployeesByDepartmentNameQuery(state.session);
    Query query2 = findEmployeesByDesignationQuery(state.session);
    Query query3 = findDepartmentOfAnEmployeeQuery(state.session);

    blackhole.consume(query1);
    blackhole.consume(query2);
    blackhole.consume(query3);
}

Обратите внимание, что мы использовали JMH для написания нашего теста.

5.3. Результаты бенчмарка

Теперь давайте визуализировать время компиляции против диаграммы размера кэша, который мы подготовили, вытехав на вышеуказанный тест:

Как мы можем ясно видеть на графике, увеличение числа запросов, которые Hibernate может кэшировать, следовательно, сокращает время компиляции .

Для размера кэша один, среднее время компиляции является самым высоким на 709 микросекунд, затем он уменьшается до 409 микросекунд для кэша размером два, и в целом до 0,637 микросекунд для кэша размером три.

6. Использование статистики спячки

Для мониторинга эффективности кэша плана запроса Hibernate предоставляет следующие методы с помощью Статистика интерфейс:

  • получить КвериПланКашХитКонт
  • получить КвериПланКашМиссКонт

Таким образом, если количество попадания высокое и количество промахов низкое, то большинство запросов подаются из самого кэша, вместо того, чтобы компилироваться снова и снова.

7. Заключение

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

Как всегда, исходный код этого учебника доступен более на GitHub .