티스토리 뷰

반응형

이전 글에서 JPA 복합키의 사용법을 알아보았는데요, 이번에는 JPA에서 선호하는 키 방법에 대해 간단히 살펴보고자 합니다.

이전 글 : https://abbo.tistory.com/329

 

JPA 복합키 (2개 이상의 PK) 사용할 때

이번에 작성할 내용은 JPA 복합키 매핑을 적용할 때 엔티티 클래스 생성하는 내용을 살펴보고자 합니다. create table push_log ( push_id bigint not null, user_id bigint not null, clicked bit not null defau..

abbo.tistory.com

 


우선 제가 사용한 방법은 Java 에서는 long Wrapper 클래스인 Long 타입, MySQL 에서는 bigint 타입을 사용하였습니다.

가장 먼저 JPA의 인덱스 처리 상 조회에서는 문제가 빈번하게 일어나는 경우 크게 없습니다. 하지만 문제는 생성/수정/삭제에 일어나게 되는데요. 아래의 조건은 기본적으로 발생하는 조건입니다.

  • JPA의 인덱스 처리는 B-Tree 알고리즘을 사용한다.
  • Primary Key는 Unique하다. 
  • 복합키는 Tuple로 관리한다. 
  • Tuple은 B-Tree를 사용하지 않는다.
  • 복합키는 인덱스이며 Unique한 값이다.
  • Unique Key는 두 개 이상에 컬럼에 같이 걸려있는 값이다.

즉, 복합키는 Unique하며 Tuple로 인식이 되기 때문에 정렬에 큰 지장이 없다. 가 결론이 되겠습니다. 다만 성능에 지장이 있는 부분은 두 개 이상의 컬럼(Unique Key Set)이 아닌 각각의 컬럼에 걸린 경우 조회시 문제가 발생할 수도 있겠습니다.

정확한 예시를 위해 저번에 작성한 클래스를 다시 가져와보겠습니다.

@Entity
@Data
@IdClass(PushLogPK.class)
public class PushLog {

    @Id
    @Column(name = "user_id")
    private Long userId;

    @Id
    @Column(name = "push_id")
    private Long pushId;

    private boolean clicked;
    
    @Data
    public static class PushLogPK implements Serializable {
        private Long pushId;
        private Long userId;
        
        public PushLogPK() {}
    }

    public PushLog() {}
    
    public PushLog(Long userId, Long pushId) {
        this.userId = userId;
        this.pushId = pushId;
    }
}

 

위의 경우 pushId, userId 두 개의 set으로 조회를 하는 경우는 큰 문제가 되지 않습니다. 하지만, pushId 별로 조회를 하거나 userId 별로 조회를 하는 경우 인덱스가 형성되어 있지 않다면, 쿼리 성능에 지연이 있을 수 있습니다. 그렇게 되는 경우 DB에 직접 접근하여 인덱스를 추가해주어야 합니다. 

 

추가로 equals(), hashCode() 메소드를 복합키 비교에서 사용하기 때문에 @Override 하여 설정하는 것이 좋습니다. 왜냐면 동등 비교로 인식을 하는 부분에서 문제가 발생하기 때문입니다. 

즉, 아래의 경우는 성립되지 않습니다.

PushLog log1 = new PushLog(1L, 2L);
PushLog log2 = new PushLog(1L, 2L);
log1.equals(log2); // false -> 메모리 주소(hashCode)가 다름

그래서 아래와 같이 Override 함수를 추가해주면 편하지 않을까 합니다.

@Override
public boolean equals(PushLog pushLog) {
    return this.userId.longValue() == pushLog.getUserId().longValue() 
        && this.pushId.longValue() == pushLog.getPushId().longValue();
}

@Override
public int hashCode() {
    return this.pushLogPK.hashCode();
}

요약하자면 아래와 같습니다.

장점

  • 성능에 지장이 없다.
  • 키를 조합하기 쉽다.

단점

  • 조합된 키만을 사용해야 한다.
  • equals(), hashCode() 함수를 구현해야 한다.

 

참고 문서

복합키 성능 비교 : https://developer-ping9.tistory.com/298

JPA에서 equals(), hashCode() 구현 이유 : https://modimodi.tistory.com/14

 

[JPA] 복합키에서 equals () 및 hashCode () 구현하는 이유

ParentId id1 = new ParentId(); id1.setId1("myId1"); id1.setId2("myId2"); ParentId id2 = new ParentId(); id2.setId1("myId1"); id2.setId2("myId2"); id1.equals(id2) ?????? id1.equals(id2) 의 결과값은 f..

modimodi.tistory.com

 

반응형
댓글
공지사항