본문 바로가기
JPA/자바 ORM 표준 JPA 프로그래밍 - 기본편

시퀀스 allocationSize 정리

by hk27 2022. 2. 4.

 

시퀀스 allocationSize의 기본값은 왜 50일까요?

 

안녕하세요. 

DB 시퀀스의 allocationSize에 대해서 알아보겠습니다.

 

이 게시글은 아래 글을 작성하며 Sequence의 allocation에 대해 궁금해져서 작성하게 된 글입니다.

JPA에서 시퀀스를 어떻게 다루는지 내용이 포함되어있으니 궁금하신 분은 아래 게시글을 참고해주세요. 

[JPA] 기본 키 매핑

 

시퀀스의 allocationSize는 단어 그대로 할당해놓는 시퀀스의 크기입니다.

시퀀스를 보통 한 개만 할당할 것 같지만, allocationSize의 기본값이 50이라는 것에 주의해야 합니다.

한번 시퀀스를 호출할 때 50개씩 시퀀스를 할당해놓는다는 것입니다. 

왜 이렇게 많이 할당해놓는지 궁금합니다. 

 

엔티티를 영속성 컨텍스트에 보관하기 위해서는 기본 키 값을 알아야 합니다. 

따라서 JPA는 call next value for BOARD_SEQ를 호출해서 시퀀스값을 가져옵니다.

트랜잭션을 지원하는 쓰기 지연을 지원하기 위해 INSERT 쿼리는 마지막에 모아서 DB에 전송하지만,

그 전에 기본키 값이 필요하기 때문에 시퀀스값만 얻어오는 것입니다.

하지만 시퀀스값을 얻어오기 위해서 persist 할 때 마다 DB에 접근하고, 네트워크를 타면 성능이 나빠질 수 있으므로 시퀀스값을 50개씩 가져옵니다. 50개만큼 DB에 할당해두고 메모리에 시퀀스값을 기록하여 사용합니다.

 

예를 들어서 allocationSize를 50으로 설정하고 엔티티를 DB에 저장해봅시다.

@Getter @Setter
@Entity
@SequenceGenerator(
        name = "BOARD_SEQ_GENERATOR", // 시퀀스 생성기 이름
        sequenceName = "BOARD_SEQ", // 실제 DB의 시퀀스
        initialValue = 1, allocationSize = 1)
public class Board {
    @Id
    @GeneratedValue(strategy = SEQUENCE, generator = "BOARD_SEQ_GENERATOR") // 방금 등록한 시퀀스 생성기 선택
    // 식별자 값은 BOARD_SEQ_GENERATOR 시퀀스 생성기가 할당함
    private Long id;
}
Board boardA = new Board();
em.persist(boardA);

 

하이버네이트는 식별자 값을 알기 위해서 call next value를 부릅니다. value가 1이겠죠.

그리고 2-51을 할당하기 위해서 call next value를 다시 부릅니다. 

Hibernate: 
    call next value for BOARD_SEQ // value 1
Hibernate: 
    call next value for BOARD_SEQ // value 2 ~ 51

 

다른 트랜잭션에서 boardB를 저장해봅시다.

Board boardB = new Board();
em.persist(boardB);

 

식별자 값을 얻기 위해 call next value 함수를 부르고, 52 ~ 101을 할당받습니다.

boardB의 식별자 값은 52가 됩니다. 

Hibernate: 
    call next value for BOARD_SEQ // value 52 ~ 101

 

DB에 저장된 값을 보면 1과 52가 저장된 것을 볼 수 있습니다. 

만약 식별자 값이 차례대로 올라야 하는 상황이면 allocationSize를 반드시 1로 설정해주셔야 합니다.

그렇지 않으면 중간에 빈값들이 생깁니다. 

 

allocationSize를 1로 설정한 예시를 봅시다. 

Board boardA = new Board();
em.persist(boardA);
Board boardB = new Board();
em.persist(boardB);
Board boardC = new Board();
em.persist(boardC);

System.out.println("========================");
System.out.println("boardA.id = " + boardA.getId()); // board.id = 1
System.out.println("========================");
System.out.println("boardB.id = " + boardB.getId()); // board.id = 2
System.out.println("========================");
System.out.println("boardC.id = " + boardC.getId()); // board.id = 3
System.out.println("========================");

 

결과 

Hibernate: 
    call next value for BOARD_SEQ
Hibernate: 
    call next value for BOARD_SEQ
Hibernate: 
    call next value for BOARD_SEQ
========================
boardA.id = 1
========================
boardB.id = 2
========================
boardC.id = 3
========================

매번 call next value 쿼리가 나가서 3번의 쿼리가 나갔습니다. 

 

이어서 board D~F를 다른 트랜잭션에서 저장해도 id 값이 이어져서 증가합니다. 

Board boardD = new Board();
em.persist(boardD);
Board boardE = new Board();
em.persist(boardE);
Board boardF = new Board();
em.persist(boardF);

System.out.println("========================");
System.out.println("boardD.id = " + boardD.getId()); // board.id = 4
System.out.println("========================");
System.out.println("boardE.id = " + boardE.getId()); // board.id = 5
System.out.println("========================");
System.out.println("boardF.id = " + boardF.getId()); // board.id = 6
System.out.println("========================");

 

수행 결과

Hibernate: 
    call next value for BOARD_SEQ
Hibernate: 
    call next value for BOARD_SEQ
Hibernate: 
    call next value for BOARD_SEQ
========================
boardD.id = 4
========================
boardE.id = 5
========================
boardF.id = 6
========================

 

 

같은 코드를 allocationSize를 50으로 설정하고 수행하면 아래와 같은 결과가 나옵니다. 

Hibernate: 
    call next value for BOARD_SEQ
Hibernate: 
    call next value for BOARD_SEQ
========================
boardA.id = 1
========================
boardB.id = 2
========================
boardC.id = 3
========================
Hibernate: 
    call next value for BOARD_SEQ
========================
boardD.id = 52
========================
boardE.id = 53
========================
boardF.id = 54
========================

 

call next value를 불러서 DB에 접근하는 숫자는 줄어들지만, id 값은 순차적으로 증가하지 않습니다.

보통은 allocationSize를 기본 값인 50으로 사용하며 성능을 최적화하고, id가 순차적으로 증가해야 하면 allocationSize를 1로 설정하면 됩니다.

 

 

참고 자료

김영한, 자바 ORM 표준 JPA 프로그래밍, 에이콘출판(2015), pp.135-138.

 

 

댓글