15. 쓰기지연

Alex·2024년 7월 19일
0

리팩토링

목록 보기
15/17
public class Accommodation {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)

IDENTITY 전략의 경우 JPA의 쓰기지연이 안될 수 있는데요.
이 부분 인지 하고 계신걸까요?모르셨다면 왜 쓰기지연이 안되는 상황이 있는지? 부터 접근을 해보시는 게 좋습니다.
자동증가 기본키가 맹목적으로 안좋다기보다는 상황에 따라 더 나은 선택지가 있는 거 같습니다.

쓰기지연

쓰기지연이란? (transactional write-behind) 영속성 컨텍스트에 변경이 발생하면 데이터베이스로 쿼리를 보내지 않고 SQL 쿼리를 버퍼에 모아둔다.

영속성 컨텍스트가 flush하는 시점에 모아둔 sql 쿼리를 db에 보낸다.

JPA 영속성 컨텍스트의 1차캐시 & 쓰기지연은 정말 동작하는가?

쓰기 지연을 하면 위 코드에서
save 쿼리가 로그 이후로 찍혀야 하지만,
실제로는 로그 이전에 쿼리가 나간다.

물론, 이는 엔티티가 id 자동증가 방식으로 설정됐을 때의 이야기다.

엔티티가 영속상태가 되려면 식별자가 꼭 필요하다.
식별자 생성전략을 IDENTITY로 사용하면 데이터베이스에 실제로 저장을 해야 식별자를 구할 수 있으므로 Insert 쿼리가 즉시 데이터베이스에 전달된다.
따라서 이 경우에 쓰기 지연을 활용한 성능 최적화를 할 수 없다.

예상은 당연히 트랜잭션이 종료될 때 UPDATE 쿼리가 날아가는 줄 알았다.
하지만 ProductItem1에서 식별자가 아닌 name필드로 쿼리를 하고있다.
식별자가 아닌 필드로 조회를 하면 조회 쿼리를 하기 전에 쓰기지연 저장소에 있던 UPDATE 쿼리를 날리고 그 이후에 조회를 한다.
이것은 트랜잭션 Isolation Level을 낮춰도 동일하게 작동된다.

batch와는 어떻게 다른가?

갑자기 공부를 하다보니 spring batch의 벌크 insert와 어떤 차이가 있는건지?...하는 의문이 들었다.

Batch Insert 성능 향상기 1편 - With JPA

쓰기 지연은 sql쿼리를 커밋시점에 한번에 보낸다는 거곡
배치 벌크인서트는 sql 쿼리 여러개를 하나로 묶어서 보내는거라고 한다... 쿼리를 하나로 보내는건가?

좀더 생각을 해보면...
gpt에게 물어보면 쓰기 지연자체가 대량 데이터를 업데이트 하는데 효율적이지는 않다고 한다...

[JPA] 벌크 연산(Bulk Operation)이란?

혹시나 싶어서 쿼리가 어떻게 나가는지 확인을 했다.

@Test
    @Transactional
    @Commit
    void test1(){
        for(Long i =1L; i<13; i++){
            Person person = personRepository.findById(i).get();
            person.setName("변경");
            System.out.println("엔티티 변경");
        }
    }

select를 다 먼저하고 변경감지라는 로그가 위에 10개가 다 뜬 상태에서
마지막을 보니 update 쿼리가 한번에 나가는 걸 볼 수 있었다.

배치를 쓰면 저게 하나의 쿼리로 나가던데... 그런 차이인건가?

배치와 jpa의 차이

쓰기 지연을 하면
쿼리가 마지막에 한번에 나간다는 것이 특징이다.

스프링 배치와의 차이는
쿼리가 여러개로 나가느냐 아니면 쿼리를 하나로 변경해서 보내느냐의 차이인거 같다.

실제로 쿼리가 여러개 나가면 성능에 영향을 줄 수 있다고 하니

그래서 배치를 쓰나보다

Spring Batch 애플리케이션 성능 향상을 위한 주요 팁

여길 보니까 더티체킹 자체가 비용이 발생한다고 한다.

profile
답을 찾기 위해서 노력하는 사람

0개의 댓글