mikonu / fastcampus-project-board

패스트캠퍼스 게시판 만들기 프로젝트. 자바 + 스프링부트와 관련 기술들을 공부한다.
https://fastcampus.co.kr/dev_online_befinal
1 stars 0 forks source link

회원 엔티티: PK를 `userId`로 바꾸기 #34

Closed mikonu closed 1 month ago

mikonu commented 1 month ago

https://github.com/mikonu/fastcampus-project-board/blob/1da46305c2d8091609eab6b07e69f0ff17aa8ce6/src/main/java/com/fastcampus/projectboard/domain/UserAccount.java#L18-L25

현재 회원 계정 엔티티는 PK로 id를 자동 채번(auto_increment)하여 쓰고 있다. 그런데 이 id운용 방식은 큰 의미가 없어 보인다. 회원 정보는 유저가 가입하면서 입력할 ID(userId)로 고유하게 특정되므로, 별다른 부작용이 없다면 userId를 PK로 쓰는 것도 효율적일 것 같다. 특히 userId를 PK로 쓰면, userId를 이용한 참조 쿼리 메소드를 편리하게 사용할 수 있는 이점이 생긴다. 이를 설계에 반영해보자.

Reference

hegunhee commented 1 month ago

안녕하세요. 궁금증이 생겨서 코멘트 남겨놓습니다. VARCHAR값을 Primary Key로 등록해서 발생하는 성능 저하가 궁금해서 코멘트 남겨놓습니다. Mysql InnoDB의 경우 Primary Key를 클러스터링 인덱스 방식으로 데이터를 저장합니다.

  1. 클러스터링 인덱스의 경우 데이터가 추가될 경우 클러스터링 인덱스 기준(*)으로 재정렬되는데요 현재 userId의 경우 string값이라 데이터 추가에 성능에 영향이 갈까 걱정됩니다.

물론 현재 JPA에서 제공하는 매서드를 편하게 사용할 수 있다는 장점은 매우 크다고 생각합니다.

  1. DB성능과 개발자의 편의성중 어떤곳에 방점을 두어야할지 궁금합니다.
mikonu commented 1 month ago

@hegunhee 좋은 질문입니다. 새 pk가 bigint -> varchar로 바뀔 경우 어떤 성능 저하가 있을지 예상하려면 1. 우선 두 자료형이 클러스터링 인덱스로 지정되었을 경우 특별한 퍼포먼스 차이가 있는지 확인해야 하고 2. 데이터 사이즈가 문제라면 두 자료형의 데이터 사이즈 차이가 얼마나 될지를 판단하면 좋겠죠.

이런 측면에서 userId의 varchar 길이를 최대 몇 자와 같이 지정해주면 퍼포먼스 저하를 최소화해줄 수 있겠죠. 그럼에도 불구하고 본질적인 퍼포먼스 차이가 있다면 다음과 같은 점들을 고려해보면 좋을 겁니다:

  1. userId를 pk로 잡을 경우 예상되는 클러스터링 인덱스 사이즈 증가치는 몇 퍼센트인가?
    • bigint 사이즈는 8 bytes
    • varchar 평균 사이즈를 중간값으로 한다고 했을 때 줄 수 있는 최대 길이는 8 * 2 - 1 = 15자 -> 길이 15를 주면 얼추 사이즈 변화가 크지 않겠다고 예상할 수 있음 (사실은 이것보다 짧게 줘야 함)
    • varchar 사이즈 30자를 허용하면 대략 자료형 변화로 인한 데이터 사이즈가 2배 이상이 될 것으로 짐작할 수 있음
    • 여기서 가지고 있는 기존 회원의 id 목록을 뽑아서 평균 길이를 계산해보는 것도 좋은 참고 자료가 될 것
  2. 예상 느려지는 퍼포먼스는 몇 퍼센트인가?
    • 조회의 경우?
    • 조작의 경우?
  3. 위 분석이 의미를 가지려면 이용하는 데이터의 사이즈 -> 예상 서비스 이용도도 어느 정도 가늠해야 한다.
    • 예상 유저 수가 얼마 없고 전체 게시글 수가 십만 건 이하, 하루 조회 트랜잭션이 십만 회 이하라면 위 고민은 큰 의미가 없을 거고 편의성에 초점을 맞춰 선택을 하게 될 것
    • 서비스 확장세가 이미 가시적으로 빠르고 조만간 예상 유저 수가 백만에 한달 뒤 게시글 수가 억 건 이상, 하루 트랜잭션이 삼십만 회 이상이라면 최적화 고민에 의미가 생기기 시작함
  4. id를 pk로 유지할경우, id는 메타정보이므로 서비스에 노출시키지 않을 전망이다. 유저를 특정하려면 userId를 쓰게 될 거고, 결국 여기에 secondary index가 적용된다.
    • userId를 clustering index 운용하기 vs. 쓰지 않는 id를 pk로 놔두고 userId를 secondary index로 운용하기
    • 이 둘의 차이와 이득을 계산해야 한다.
    • userId를 secondary index로 운용하는 경우라도, pk index가 여전히 존재한다는 점도 생각해야 한다.
  5. 마지막으로 jpa 코드 사용 이점까지 점검
    • userId가 pk가 아니라면 별도로 해당 키를 where절 검색하는 쿼리 메소드를 작성해줘야 하고, 엔티티 참조만을 가져오는 lazy loading의 이점을 간단하게 활용할 수도 없다.

이 점을 모두 고려하면, userId를 pk로 설정하여 보는 손해가 어느 정도인지를 좀 더 명확하게 가늠할 수 있게될 겁니다. 저는, 결론부터 말하면 성능 저하 부작용이 우려할 수준에 이르지 않는다고 생각합니다. +강의라는 특수한 상황이라 id pk를 쓰지 않는 상황을 직접 실습하는 기회를 주는 목적도 있음을 기억하세요.

db 성능과 개발자의 편의성 중 어디를 선택해야 하는가? 는 당연히 둘 다 중요한 가치이기 때문에 일괄적으로 판단할 수 없습니다. 관례도 살펴보고, 우리 서비스의 특성과 상황을 중심으로 고려해야 합니다. 당연히 작업하기 전에 논의를 거치는 것이 좋겠죠. 그래서 최선의 답을 선택하고 진행하도록 합니다.

Reference