복붙노트

[SPRING] Hibernate가있는 Spring Data JPA의 생성자 예측 및 엔티티 예측보다 인터페이스 투영이 왜 느린 이유는 무엇입니까?

SPRING

Hibernate가있는 Spring Data JPA의 생성자 예측 및 엔티티 예측보다 인터페이스 투영이 왜 느린 이유는 무엇입니까?

나는 어떤 종류의 투영법을 사용해야하는지 궁금해했다. 그래서 나는 5 가지 유형의 투영법을 다루는 약간의 테스트를 수행했다. (문서에 기초 : https://docs.spring.io/spring-data/jpa/docs/current / reference / html / # projections) :

1. 개체 투영

이것은 스프링 데이터 저장소가 제공하는 표준 findAll ()입니다. 아무것도 여기에 공상.

서비스:

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;
    }
}

몇 가지 추가 정보 :

이 프로젝트는 스프링 5.0.8을 사용하는 gradle spring boot plugin (버전 2.0.4)을 사용하여 만들었습니다. 데이터베이스 : 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에 별명이 필요하며 .getName () 대신 .get ( "name")을 호출하여 데이터를 검색해야합니다.

동적 인 투영은 매우 멋있고 빠르지 만 정확하게 하나의 생성자를 가져야합니다. 그 이상도 이하도 아닌. 그렇지 않으면 Spring 데이터는 사용할 데이터를 알지 못하기 때문에 예외를 throw합니다. DB에서 가져올 데이터를 결정하기 위해 생성자 매개 변수를 사용합니다.

의문:

엔티티를 가져 오는 것보다 인터페이스 투영에 시간이 오래 걸리는 이유는 무엇입니까? 반환 된 각 인터페이스 프로젝션은 실제로 프록시입니다. 프록시를 만드는 것이 너무 비쌉니까? 그렇다면 그것이 투영의 주요 목적을 이기지 못하나? 다른 투상은 두려운 tho를 본다. 나는 이것에 대한 통찰을 정말 좋아할 것이다. 고맙습니다.

편집하다 : 다음은 테스트 저장소입니다. https://github.com/aurora-software-ks/spring-boot-projections-test. 직접 실행하려는 경우에 대비하십시오. 설정하는 것은 매우 쉽습니다. Readme에는 알아야 할 모든 것이 들어 있습니다.

해결법

  1. ==============================

    1.스프링 데이터의 이전 버전과 비슷한 동작을 경험했으며 이것이 내 작업입니다 : https://blog.arnoldgalovics.com/how-much-projections-can-help/

    스프링 데이터의 이전 버전과 비슷한 동작을 경험했으며 이것이 내 작업입니다 : https://blog.arnoldgalovics.com/how-much-projections-can-help/

    나는 Oliver Gierke (Spring Data Lead)와 대화를 나누었고 몇 가지 개선 사항을 만들었습니다. 그래서 당신은 "좋은"결과를 얻었습니다 :-)) 기본적으로 수동으로 코딩하는 것에 비해 추상화에 대한 비용이 항상 있습니다.

    이것은 다른 모든 것과 마찬가지로 절충안입니다. 한편으로 유연성, 쉬운 개발, 적은 유지 보수 (잘하면), 다른 한편으로 당신이 완전히 통제, 좀 못생긴 쿼리 모델을 얻을.

  2. from https://stackoverflow.com/questions/53347063/why-are-interface-projections-much-slower-than-constructor-projections-and-entit by cc-by-sa and MIT license