복붙노트

[SPRING] 스프링 데이터 나머지로 n + 1 쿼리를 피하는 방법은 무엇입니까?

SPRING

스프링 데이터 나머지로 n + 1 쿼리를 피하는 방법은 무엇입니까?

의문. Spring Data REST로 n + 1 개의 쿼리를 피하는 방법은 무엇입니까?

배경. 리소스 목록에 대해 Spring Data REST를 질의 할 때, 연결된 최상위 리소스에 직접적으로 임베디드되는 것과는 대조적으로 결과로 나타나는 최상위 리소스 각각은 관련 리소스에 대한 링크를 갖습니다. 예를 들어 데이터 센터 목록을 쿼리하면 연결된 지역이 다음과 같이 링크로 표시됩니다.

{
  "links" : [ {
    "rel" : "self",
    "href" : "http://localhost:2112/api/datacenters/1"
  }, {
    "rel" : "datacenters.DataCenter.region",
    "href" : "http://localhost:2112/api/datacenters/1/region"
  } ],
  "name" : "US East 1a",
  "key" : "amazon-us-east-1a"
}

그러나 n + 1 쿼리를 수행하지 않고도 관련 정보를 얻으려는 것이 일반적입니다. 위 예제를 고수하기 위해 UI에 데이터 센터 및 관련 영역 목록을 표시하고자 할 수 있습니다.

내가 뭘했는지. 내 RegionRepository에 대한 사용자 지정 쿼리를 만들어 주어진 데이터 센터 키 집합에 대해 모든 영역을 가져 왔습니다.

@RestResource(path = "find-by-data-center-key-in")
Page<Region> findByDataCentersKeyIn(
    @Param("key") Collection<String> keys,
    Pageable pageable);

유감스럽게도이 쿼리가 생성하는 링크는 위의 데이터 센터 쿼리가 생성하는 링크와 겹치지 않습니다. 다음은 커스텀 질의를위한 링크입니다 :

http://localhost:2112/api/regions/search/find-by-data-center-key-in?key=amazon-us-east-1a&key=amazon-us-east-1b

{
  "links" : [ ],
  "content" : [ {
    "links" : [ {
      "rel" : "self",
      "href" : "http://localhost:2112/api/regions/1"
    }, {
      "rel" : "regions.Region.datacenters",
      "href" : "http://localhost:2112/api/regions/1/datacenters"
    }, {
      "rel" : "regions.Region.infrastructureprovider",
      "href" : "http://localhost:2112/api/regions/1/infrastructureprovider"
    } ],
    "name" : "US East (N. Virginia)",
    "key" : "amazon-us-east-1"
  }, {
    "links" : [ {
      "rel" : "self",
      "href" : "http://localhost:2112/api/regions/1"
    }, {
      "rel" : "regions.Region.datacenters",
      "href" : "http://localhost:2112/api/regions/1/datacenters"
    }, {
      "rel" : "regions.Region.infrastructureprovider",
      "href" : "http://localhost:2112/api/regions/1/infrastructureprovider"
    } ],
    "name" : "US East (N. Virginia)",
    "key" : "amazon-us-east-1"
  } ],
  "page" : {
    "size" : 20,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 1
  }
}

데이터 센터 쿼리가 이미 데이터의 모양을 이해하고 나면 특별히 유익하지 않은 링크를 반환하는 것 같습니다. 예를 들어, 데이터 센터 1의 지역이 / datacenters / 1 / region에 있다는 것을 이미 알고 있으므로 어떤 특정 지역이 관련되어 있는지에 대한 실제 정보를 원한다면 링크를 따라 가야합니다. 특히 대량 쿼리에서 표시되는 표준 URI를 얻기 위해 링크를 따라야 만 n + 1 쿼리를 피할 수 있습니다.

해결법

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

    1.Spring Data REST가 이와 같이 작동하는 이유는 다음과 같습니다. 기본적으로 모든 애플리케이션 저장소는 REST 서비스의 기본 리소스라고 가정합니다. 따라서 엔티티의 관련 객체에 대한 저장소를 노출하면 링크가 렌더링되고 중첩 된 자원 (예 : foo / {id} / bar)을 통해 하나의 엔티티가 다른 엔티티로 할당됩니다.

    Spring Data REST가 이와 같이 작동하는 이유는 다음과 같습니다. 기본적으로 모든 애플리케이션 저장소는 REST 서비스의 기본 리소스라고 가정합니다. 따라서 엔티티의 관련 객체에 대한 저장소를 노출하면 링크가 렌더링되고 중첩 된 자원 (예 : foo / {id} / bar)을 통해 하나의 엔티티가 다른 엔티티로 할당됩니다.

    이를 방지하려면 관련 리포지토리 인터페이스에 @RestResource (exported = false) 주석을 달아줍니다. 그러면이 리포지토리에서 관리하는 엔터티가 최상위 리소스가되지 않습니다.

    보다 일반적인 접근 방법은 Spring Data REST로 시작하여 관리하고자하는 리소스와 기본 규칙이 적용되도록하는 것입니다. 그런 다음 ResourceProcessor 를 구현하고 구현을 Spring bean으로 등록하여 렌더링 및 링크를 사용자 정의 할 수 있습니다. 그러면 ResourceProcessor가 렌더링 된 데이터를 사용자 정의하고 표현에 추가 된 링크 등을 사용자 정의 할 수 있습니다.

    그 외 모든 경우 컨트롤러를 수동으로 구현하고 (기본 컨트롤러의 URI 공간에 블렌딩 할 수도 있음) ResourceProcessor 구현을 통해 링크를 추가하십시오. 이 예제는 Spring RESTBucks 샘플에서 볼 수있다. 샘플 프로젝트는 Spring Data REST를 사용하여 Order 인스턴스를 관리하고보다 복잡한 지불 프로세스를 구현하는 맞춤 컨트롤러를 구현한다. 그 외에도 Order 리소스에 대한 링크를 추가하여 수동으로 구현 된 코드를 가리 킵니다.

  2. ==============================

    2.Spring Data REST는 Jackson ObjectMapper 내에 구성된 serializer가 Spring Data REST 내부에서 사용되는 특별한 종류의 Resource 인 PersistentEntityResource를보고 트리거되는 경우에만 설명하는 표현을 작성합니다.

    Spring Data REST는 Jackson ObjectMapper 내에 구성된 serializer가 Spring Data REST 내부에서 사용되는 특별한 종류의 Resource 인 PersistentEntityResource를보고 트리거되는 경우에만 설명하는 표현을 작성합니다.

    ResourceProcessor >를 생성하고 새로운 Resource (origResource.getContent (), origResource.getLinks ())를 반환하면 기본 Spring 데이터 REST 직렬화 기계가 트리거되지 않고 Jackson의 일반적인 직렬화 규칙 적용됩니다.

    그러나 JSON에 직렬화 할 때 객체 그래프를 임의로 탐색하는 것을 매우 어렵게하기 때문에 Spring Data REST가 연관을 수행하는 이유가 있습니다. 연관을 처리하는 방식으로 직렬화가 N 레벨의 오브젝트 그래프를 탐색하기 시작하지 않으며 퍼포먼스가 훨씬 느려지고 over-the-wire로 진행되는 표현의 성능이 향상됩니다.

    Jackson이 기본 구성에서 수행중인 PersistentEntityResource를 직렬화하려고 시도하지 않도록 보장하기 위해 연관의 스프링 데이터 REST 처리가 트리거되지 않도록합니다. 물론이 점에서 스프링 데이터 REST의 도우미가 트리거되지 않습니다. 관련 리소스에 대한 링크가 여전히 필요한 경우에는 해당 리소스를 직접 만들고이를 일반 리소스에 추가해야합니다.

  3. from https://stackoverflow.com/questions/15886897/how-do-i-avoid-n1-queries-with-spring-data-rest by cc-by-sa and MIT license