성능 최적화(읽기전용 쿼리)

Mina Park·2022년 12월 3일
0

1. 성능 최적화의 필요성

  • 영속성 컨텍스트에서 엔티티가 관리될 경우
    • 장점: 1차 캐시, 변경감지 등
    • 단점: 메모리 사용 증가(변경감지를 위해 스냅샷 인스턴스를 보관)
  • 단순 조회성인 경우 읽기 전용으로 엔티티 조회하여 메모리 사용량 최적화

2. 쿼리 최적화 방법

1) 스칼라 타입으로 조회

  • 스칼라 타입 프로젝션: 숫자, 문자, 날짜 등 기본 데이터 타입
  • 엔티티가 아닌 스칼라 타입으로 모든 필드를 조회 => 영속성 컨텍스트에서 관리 X
	select o.id, o.name, o.price from Order p

2) 읽기전용 쿼리 힌트 사용

  • 하이버네이트 전용 힌트인 org.hibernate.readOnly 사용
    • Ex)수정 메소드에 적용 => 변경감지가 일어나지 않으므로 update 쿼리실행 X
	@Transactional
	public Long updateBoard(UpdateBoardDTO updateBoardDTO) {
		Board found = boardRepository.findByIdReadOnly(updateBoardDTO.getId());
		Board changed = found.changeBoard(updateBoardDTO);

		return changed.getId();
	}
   @Query(value = "select b from Board b" +
          " where b.id = :id")
    @QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))
    Board findByIdReadOnly(@Param("id") Long id);

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

  • 스프링 프레임워크가 해당 어노테이션이 있을 경우 하이버네이트 세션 플러시 모드를 MANUAL로 설정
    • 강제로 플러시를 호출하지 않는 한 플러시 X
  • 따라서 트랜잭션 커밋 시점에도 영속성 컨텍스트 플러시 X => 데이터 등록,수정,삭제 X

[참고] hibernate가 제공하는 flush mode

  • ALWAYS, AUTO(default), COMMIT, MANUAL

4) 트랜잭션 밖에서 읽기

  • 트랜잭션 없이 엔티티 조회
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)

[참고] transaction propagation option

📌 [정리] 경우에 따른 읽기전용 데이터의 성능 최적화

  • [1] 메모리를 최적화하자
    • 스칼라 타입으로 조회
    • 하이버네이트가 조회하는 읽기전용 쿼리 힌트 사용
  • [2] 플러시 호출을 막자
    • 읽기전용 트랜잭션
    • 트랜잭션 밖에서 읽기
  • 위 두 가지를 동시에 사용하는 것이 가장 효과적
@Transactional(readOnly = true)
	public Page<BoardListDTO> getBoardList(String keyword, Pageable pageable) {
		//페이징 처리
		//일대다인 boardReplyList의 경우 지연로딩+batch size 옵션 사용
		Page<Board> board = boardRepository.findAllPaging(keyword, pageable);
		Page<BoardListDTO> res = BoardListDTO.toBoardListDTO(board);

		return res;
	}
    @Query(value = "select b from Board b" +
            " where ((b.title like concat('%', :keyword, '%')" +
            " or b.content like concat('%', :keyword, '%'))" +
            " or (:keyword is null or :keyword = ''))" +
            " order by b.createdAt desc")
    @QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))
    Page<Board> findAllPaging(@Param("keyword") String keyword, Pageable pageable );

0개의 댓글