TIL(23) : 복합키에 대한 모든것

Thomas·2023년 7월 31일
0
post-thumbnail

오늘 강의에서 연관관계 매핑 심화부분에서 복합키 사용하기부분을 하다가 이전에 복합키에 대해서 적을려다가 못 적은게 생각이 나서 같이 합쳐서 적을려고 한다.

복합키란?

일단 우리가 알고 있듯이 PK 1개를 사용하면 단일키
FK 2개를 사용하는 경우 복합키이다!
그래서 PK없이 복합키를 사용할 수 있다!

복합키 사용하기

복합키를 선언하는 방법은 2가지가 있다.
1. @IdClass를 활용하는 복합키는 복합키를 사용할 엔티티 위에 @IdClass(식별자 클래스) 사용

@Entity
@IdClass(UserChannelId.class)
public class UserChannel {
  ....

  @Id
  @ManyToOne
  @JoinColumn(name = "user_id")
  User user;

  @Id
  @ManyToOne
  @JoinColumn(name = "channel_id")
  Channel channel;
  ...
}
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class UserChannelId implements Serializable {
  private Long user;   // UserChannel 의 user 필드명과 동일해야함
  private Long channel; // UserChannel 의 channel 필드명과 동일해야함

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    UserChannelId userChannelId = (UserChannelId) o;
    return Objects.equals(getUser(), userChannelId.getUser()) && Objects.equals(getChannel(), userChannelId.getChannel());
  }

  @Override
  public int hashCode() {
    return Objects.hash(getUser(), getChannel());
  }
}

ID값을 비교해주기 위해 equals랑 hashCode를 재정의(Override)를 해준다.

  1. @EmbeddedId를 활용하는 복합키는 복합키 위에 @EmbeddedId 사용
@Entity
public class UserChannel {

  @EmbeddedId
  private UserChannelId userChannelId;

	...

  @ManyToOne
  @MapsId("user_id")
  User user;

  @ManyToOne
  @MapsId("channel_id")
  Channel channel;

	...

}
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Embeddable
public class UserChannelId implements Serializable {

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

  @Column(name = "channel_id")
  private Long channelId;

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    UserChannelId userChannelId = (UserChannelId) o;
    return Objects.equals(getUser(), userChannelId.getUser()) && Objects.equals(getChannel(), userChannelId.getChannel());
  }

  @Override
  public int hashCode() {
    return Objects.hash(getUser(), getChannel());
  }
}

@IdClass랑 다른 점은 @EmbeddedId 사용이랑 선언 위치가 다르고
@MapsId를 필드위에 선언해주는데 Id Class 즉 위에 예제에선 UserChannelId에 있는 필드랑 매핑이 되어야 해서 Embeedable하게 복합키가 생성 되도록 해준다.


이전 프로젝트 때 팀원분 한 분이 Follow 엔티티랑 User 엔티티 연관관계를 복합키를 쓰셨다. 인스타 클론코딩에서 사용을 해서 가져왔다고 해서 제가 맡은 Like 즉, 좋아요 기능 구현할 때 도입을 하면 좋을까? 생각을 했었는데...

과연 이 방법이 좋은 설계일까라는 의문점이 들어 구글링을 먼저 해보았다!

구글링 해 본 결과 "특정 데이터를 식별하는 게 의미가 없는 도메인"일 떄 복합키를 구성한다고 적혀있는데 도저히 이해가 가지 않아서 튜터님한테 여쭤보았다.

일단 튜터님은 실무에선 안 쓴다고하시면서 복합키에 대해서 잘 알지 못하였다!

그래서 DB를 잘 아시는 다른 튜터님한테 여쭤 본 결과 답은 역시 똑같았다.

추가적으로 돌아오는 답변은 만약에 복합키를 쓰게 된다면

최소한 자료형은 Integer, Integer으로 키가 구성이 되고, 그 두개가 생성, 수정 및 삭제가 별로 안 일어나는 테이블이면 복합키를 사용할거 같다고 하셨다.

String으로 Key 설정하는거 보다 Integer으로 Key 설정 하는것이 좀더 성능적으로 속도가 빠르게 나온다!!

실험으로 String으로만 인덱스로 구성을 하고 대량의 데이터 조회를 하는거랑 Intger로 하는거랑 비교를 해보면 바로 알수 있을 것이다! 또한 삽입, 삭제도 해보면 좋을듯 하다!

그리고 인덱스는 이진트리 자료구조를 사용하기 떄문에 조회떄 가장 큰 빛을 본다!

DB 설계는 답이 없다... 어떻게든 조회가 되면 되는것이기 떄문에 그래서 설계할 떄 주의해야 할것은 데드라인이 중요하다! 본인이 가진 시간이 얼마나 주어졌냐에 따라 DB 최적화를 할 수 있기 때문이다! 현재 데드라인이 다가왔으면 효율적인 설계는 사실상 포기를 해야한다.

profile
Backend Programmer

0개의 댓글