🥕
TIL
  • [TIL] Studying tech / computer science knowledge
  • KeyMap
  • 알고리즘
    • 복잡도 계산 ( Computational Complexity )
    • DisjointSet-unionFind
    • Bellman-ford Algorithm
    • Dijkstra's Algorithm
    • DP ( Dynamic Programming , 동적 계획법 )
    • 플로이드-워셜 알고리즘 (Floyd-Warshall algorithm)
    • Kruskal's Algorithm
    • 최장 증가 수열 (Longes Increasing Subsequence)
    • Prim's Algorithm
    • 정렬
    • 시간복잡도 와 공간복잡도 ( Time Complexity & Space Complexity )
    • Topological Sort (위상 정렬)
  • 책 읽고난 후 요약
    • 프로그래밍 대회에서 배우는 알고리즘 문제해결 전략
    • cleancode
    • 도메인 주도 설계로 시작하는 마이크로서비스 개발
    • 오브젝트
  • CDC
    • debzium
    • kafka
  • 개발 상식
    • asciidoctor
    • 컴파일러
    • ELK 스택
    • 엔디안
    • git
    • Gitmoji
    • 테스트 종류
    • 라이브러리와 프레임워크
    • 정규 표현식
    • REST API
    • 동기와 비동기 / Blocking과 NonBlocking
    • Transaction Script와 Domain Model
    • 디자인 패턴
      • 행동 패턴
      • 객체 생성 패턴
        • 추상 팩토리 패턴
        • 빌더 패턴
        • 팩토리 메서드 패턴
        • [생성 패턴] 프로토 타입 (Prototype Parttern)
        • 싱글톤
      • 구조 패턴
        • 어댑터 패턴
        • 브릿지 패턴
        • 컴포짓(Composite) 패턴
        • 데코레이터
        • 프록시
    • refactoring
      • 중복 코드
      • 전역 데이터
      • 긴 함수
      • 긴 매개변수 목록
      • 가변 데이터
      • 이해하기 힘든 이름
  • 자료구조
    • AVL Tree
    • Splay Tree
    • aaTree
    • array-list
    • 자료구조 시간/공간 복잡도
    • 그래프
    • 힙
    • Red Black Tree
    • stack-queue
    • 트리 ( Tree )
  • DevOps
    • MSA
    • Kubernetes
      • AccessingAPI
      • controller
      • dashboard
      • kubernetes
      • object
      • pod
      • service
      • volume
  • Java
    • 어노테이션
    • 제어문
    • 데이터 타입
    • Enum
    • jvm
    • 연산자
    • thread
    • Java8
      • CompletableFuture
      • Date/Time
      • 어노테이션과 메타스페이스
      • 인터페이스
      • 람다식
      • Optional
      • 스트림
  • JavaScript
    • moduleProject
    • webpack-babel
    • 코어 자바스크립트
      • array
      • 함수 바인딩
      • 데코레이터와 포워딩
      • Class
      • 비교 연산자
      • Date 내장 객체
      • destructuring-assignment
      • function
      • 함수의 prototype 프로퍼티
      • 가비지 컬렉션 ( Garbage Collection )
      • JSON (JavaScript Object Notation)
      • map-set
      • 내장 프로토타입
      • new연산자와 생성자 함수
      • 객체
      • Object.keys, values, entries
      • 옵셔널 체이닝 '?.'
      • 프로퍼티 플래그
      • 프로퍼티 종류
      • 프로토 타입
      • 호출 스케줄링 ( scheduling a call )
      • scope
      • this
      • type-conversions
      • type
      • 함수의 자료형
      • var_let_const
  • Linux
    • 기본 명령어
    • 파일 종류
    • 리눅스
  • 네트워크
    • 응용 계층 ( Application Layer )
    • 오류 검출과 오류 정정
    • Http
    • Http Header
    • 컴퓨터 네트워크란
    • 네트워크 계층
    • 네트워크 제어 영역
    • 전송 계층 ( Transport Layer )
  • PHP
    • Facade
    • composer
    • scopeResolutionOperator
    • Laravel
      • SocialProvider
      • architecture
      • blade
      • controller
      • db
      • dbArchitecture
      • debug
      • eloquent
      • email
      • event
      • exceptionHandling
      • middleware
      • model
      • modelFactory
      • pagingLoading
      • queryBuilder
      • route
      • scout
      • seeding
      • tntsearch
      • validate
      • view
  • React
    • Next.js
    • React 란?
  • Spring
    • Controller
    • 요청이 들어왔을때 스프링이 처리하는 방법 ( 내부구조 )
    • ConfigurationProperties
    • Entity / DTO / VO
    • Maven
    • Repository와 DAO
    • 스프링 빈
    • Spring Framework
    • MVC 패턴
    • 도메인 입력값 검증
    • Spring Cloud
      • Spring Cloud
      • Eureka
    • Spring Data
      • JPA
      • JPA 어노테이션
      • 엔티티 비교
      • 복합 키와 식별 관계 매핑
      • JPA 예외처리
      • 객체지향 쿼리
      • EntityManagerFactory와 EntityManager
      • JPA 최적화
      • 프록시와 연관관계 맵핑
      • 연관관계
      • 상속관계 맵핑
      • 트랜잭션 범위와 영속성 컨텍스트
      • 데이터 타입
      • MySQL 연결
      • Pageable
    • Spring Project들과 library
      • Custom Serialize
      • Elasticsearch Index API
      • Spring HATEOAS
      • lombok (롬복)
      • Model Mapper
      • Object Mapper
      • Representation Model
      • Spring REST Docs
      • Spring Boot
    • Spring Security
      • Spring Security
      • Authentication
      • Authentication Filter
      • Authorization Filter
      • Filter Chain
      • SecurityContext
      • Spring OAuth2.0
    • Spring Test
      • AssertJ
      • Junit5
      • JunitParams
      • Mock Object
  • DataBase
    • ALIAS
    • CONCAT
    • CTE
    • Group By
    • HAVING
    • IFNULL
    • 인덱스
    • JOIN
    • ORDER BY
    • ROLLUP
    • SELECT
    • SELECT DISTINCT
    • SQL
    • WHERE
  • Web 상식
    • OAuth
    • WAS
    • HTTP통신 기반 인증
    • 브라우저
    • CSR 과 SSR
    • HTTPS
    • Web
Powered by GitBook
On this page
  • N+1 문제
  • 즉시로딩
  • 지연로딩
  • 해결방법
  • 읽기전용 쿼리 최적화
  • 1. 스칼라 타입으로 조회
  • 2. 쿼리 힌트 사용
  • 3. 읽기 전용 트랜잭션 사용
  • 4. 트랜잭션 밖에서 읽기
  • Reference
  1. Spring
  2. Spring Data

JPA 최적화

N+1 문제

즉시로딩이던지 지연로딩이던지 문제는 발생한다.

즉시로딩

Memeber와 Order가 1:N의 관계를 맺고있다고 했을때 em.find(Member.class,id)와 같은 메서드를 이용한다면 JOIN을 통한 SQL문이 실행되면서 문제없이 한번에 로딩이 된다.

em.createQuery("select m from Member m", Memeber.class).getResultList();

하지만 위와같이 JPQL을 이용할때 위와같은 JPQL을 가지고 SQL문을 생성하기 때문에 select * from member로 member를 한 번 조회하고 memberid를 외래키로 연관된 order컬럼들을 N번 조회를 하게 되는 N+1 문제가 발생한다.

지연로딩

em.createQuery("select m from Member m", Memeber.class).getResultList();

위와같이 JPQL을 사용하면 처음의 Member만 조회하고 Order 리스트는 프록시로 갖고있기 때문에 SQL문은 한번만 실행되지만 getOrder() 모든 Order를 조회하고자 한다면 이 또한 N번 실행되며 N+1 문제가 발생한다.

N+1은 ORM이라면 DB와 객체라는 특성상의 괴리로 발생하는 대표적인 문제이다.

해결방법

1. 패치 조인 사용

JPQL의 join fetch를 이용해 명시적으로 즉시로딩을 수행하면 N+1문제가 발생하지 않는다. (일대다 관계에서 조인을 해서 즉시로딩으로 가져오면 1의 중복된 결과데이터가 나타날 수 있기 때문에 JPQL의 distinct를 사용하는 것이 좋다.)

2. @BatchSize

하이버네이트가 제공하는 어노테이션을 이용하여 한번에 연관된 데이터를 조회할 개수를 지정할 수 있다.

IN절을 이용하여 지정한 사이즈 개수만큼의 데이터를 가져오는 SQL문을 생성해서 가져오고 즉시로딩으로 설정이 되어있다면 실제 데이터 개수 / BatchSize 만큼의 SQL문이 실행되기 때문에 N+1문제를 어느정도 완화가 가능하다.

지연로딩이라면 In절을 이용해 BatchSize만큼의 데이터를 한번 조회하고 그 다음을 조회하려고 할때 그 이후의 BatchSize만큼의 데이터를 다시 조회한다.

3. @Fetch(FetchMode.SUBSELECT)

연관관계를 갖는 컬럼에 패치모드를 SUBSELECT로 설정하면 JPQL의 where절이 In 내부의 sub쿼리로 수행되어 데이터를 한번에 가져온다.

-- SQL
select m from Member m where m.id > 10

-- JPQL
select o from orders o
    where o.member_id in (
        select m.id
        from member m
        where m.id > 10
    )

읽기전용 쿼리 최적화

수정, 조회도 다시 안할 단순 보여주기용의 대용량 읽기 쿼리의 같은 경우는 읽기전용으로 엔티티 조회시 메모리사용량을 최적화 할 수 있다.

--JPQL
select o from Order o

1. 스칼라 타입으로 조회

select o.id, o.name, o.price from Order P

스칼라 타입은 영속성 컨텍스트가 결과를 관리하지 않는다.

2. 쿼리 힌트 사용

하이버네이트가 제공하는 readOnly힌트를 이용해서 읽기전용으로 조회할 수 있다.

TypedQuery<Order> query = em.createQuery("select o from Order o", Order.class);
query.setHint("org.hibernate.readOnly",true);

3. 읽기 전용 트랜잭션 사용

@Transaction(readOnly = true)옵션을 이용하면 하이버네이트 세션의 플러시 모드를 MANUAL로 설정해서 강제로 플러시를 호출 하지 않는 한 플러시가 일어나지 않아 스냅샷과 같은 로직을 수행하지 않기때문에 성능이 향상된다.

하지만, 트랜잭션 시작, 로직 수행, 커밋의 과정은 이루어진다.

4. 트랜잭션 밖에서 읽기

@Transaction(propagation = Propagation.NOT_SUPPORTED)옵션을 이용하면 아예 트랜잭션 없이 조회를 수행하기 때문에 커밋 자체를 수행하지 않는다.

메모리를 최적화하기 위해서는 1,2와 같은 방법을 이용하고 플러시/커밋을 막아 속도를 최적화하려고한다면 3,4번의 방법을 이용하면 된다.


Reference

자바 ORM 표준 JPA 프로그래밍 책 (김영한 저)

PreviousEntityManagerFactory와 EntityManagerNext프록시와 연관관계 맵핑

Last updated 3 years ago