Почему проекции интерфейса намного медленнее, чем проекции конструктора и проекции сущностей в Spring Data JPA с Hibernate? - PullRequest
0 голосов
/ 17 ноября 2018

Мне было интересно, какой тип проекций мне следует использовать, поэтому я провел небольшой тест, который охватывал 5 типов проекций (на основе документов: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections):

1. Проекция объекта

Это просто стандарт findAll(), предоставляемый репозиторием Spring Data. Ничего особенного.

Служба:

List<SampleEntity> projections = sampleRepository.findAll();

Объект:

@Entity
@Table(name = "SAMPLE_ENTITIES")
public class SampleEntity {
    @Id
    private Long id;
    private String name;
    private String city;
    private Integer age;
}

2. Конструктор проекции

Служба:

List<NameOnlyDTO> projections = sampleRepository.findAllNameOnlyConstructorProjection();

Репозиторий:

@Query("select new path.to.dto.NameOnlyDTO(e.name) from SampleEntity e")
List<NameOnlyDTO> findAllNameOnlyConstructorProjection();

Объект передачи данных:

@NoArgsConstructor
@AllArgsConstructor
public class NameOnlyDTO {
    private String name;
}

3. Проекция интерфейса

Служба:

List<NameOnly> projections = sampleRepository.findAllNameOnlyBy();

Репозиторий:

List<NameOnly> findAllNameOnlyBy();

Интерфейс:

public interface NameOnly {
    String getName();
}

4. Проекция кортежа

Служба:

List<Tuple> projections = sampleRepository.findAllNameOnlyTupleProjection();

Репозиторий:

@Query("select e.name as name from SampleEntity e")
List<Tuple> findAllNameOnlyTupleProjection();

5. Динамическая проекция

Служба:

List<DynamicProjectionDTO> projections = sampleRepository.findAllBy(DynamicProjectionDTO.class);

Репозиторий:

<T> List<T> findAllBy(Class<T> type);

Объект передачи данных:

public class DynamicProjectionDTO {

    private String name;

    public DynamicProjectionDTO(String name) {
        this.name = name;
    }
}


Некоторая дополнительная информация:

Проект был построен с использованием загрузочного разъема Gradle Springджин (версия 2.0.4), который использует Spring 5.0.8 под капотом.База данных: H2 в памяти.

Результаты:

Entity projections took 161.61 ms on average out of 100 iterations.
Constructor projections took 24.84 ms on average out of 100 iterations.
Interface projections took 252.26 ms on average out of 100 iterations.
Tuple projections took 21.41 ms on average out of 100 iterations.
Dynamic projections took 23.62 ms on average out of 100 iterations.
-----------------------------------------------------------------------
One iteration retrieved (from DB) and projected 100 000 objects.
-----------------------------------------------------------------------

Примечания:

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

Проекции конструктора действительно быстрые и не имеют ограничений на стороне DTO, но требуют ручного создания объектов в аннотации @Query.

Проекции интерфейса оказались очень медленными.См. Вопрос.

Проекции кортежей были самыми быстрыми, но не самыми удобными для игры.Им нужен псевдоним в JPQL, и данные должны быть получены путем вызова .get("name") вместо .getName().

Динамические проекции выглядят довольно круто и быстро, но должны иметь ровно один конструктор.Не больше, не меньше.В противном случае Spring Data выдает исключение, потому что не знает, какой использовать (для определения данных, которые нужно извлечь из БД, нужны параметры конструктора.

Вопрос:

Почему проекции интерфейса занимают больше времени, чем извлечение объектов?Каждая возвращаемая проекция интерфейса на самом деле является прокси.Это так дорого, чтобы создать этот прокси?Если так, разве это не противоречит главной цели проекций (поскольку они должны быть быстрее, чем объекты)?Другие прогнозы выглядят потрясающе.Мне бы очень хотелось немного разобраться в этом.Спасибо.

РЕДАКТИРОВАТЬ: Вот тестовый репозиторий: https://github.com/aurora-software-ks/spring-boot-projections-test на случай, если вы хотите запустить его самостоятельно.Это очень легко настроить.Readme содержит все, что вам нужно знать.

1 Ответ

0 голосов
/ 01 декабря 2018

Я сталкивался с подобным поведением в более старой версии Spring Data, и это было мое мнение: https://blog.arnoldgalovics.com/how-much-projections-can-help/

Я поговорил с Оливером Гирке (руководитель Spring Data), и он сделал некоторые улучшения (вот почему вы получаете такие «хорошие» результаты :-)), но в основном всегда будет стоить наличие абстракций по сравнению с кодированием вручную.

Это компромисс, как и все остальное. С одной стороны, вы получаете гибкость, более простую разработку, меньше обслуживания (надеюсь), с другой стороны, вы получаете полный контроль, немного более уродливая модель запросов.

...