DB에 기본키 위임이 추세인 이유?
- 최근에 JPA, Spring Data JPA 와 같은 ORM 들의 강세로, Primary Key 생성 전략을 DB 에 위임하는 추세가 늘어나고 있다. 이러한 방식의 문제점은 무엇일까 가만히 생각해보니, 데이터베이스 자체의 의미론적으로 봤을때 , 별 의미없는 값이라고 생각될 수 있기 때문이다 (Entity 기준)
위임시의 장점 혹은 단점
- 엔티티에서 복합키를 통해 Primary Key 로 쓰기에는 Index 의 크기가 비대해질 수도 있다.
- DB 에 기본 생성 전략이 더 좋은 방향일 수도 있다.
- 쓰기 쉽다는 것도 한목하는것 같다. (제일 큰것 같다 사실)
- 단점은 Server-Side 에서 Repository 를 거치지 않을 경우 (Aggregate Root 혹은 부모 관계를 통해서 추가되는 경우) ID 값을 찾아오는 것이 불가능하거나, 힘들수도 있다는 것이다.
내가 Spring Data JDBC 를 어려워 한 이유
- 사실 아직 DDD 라는 개발 패턴을 잘 이해하지 못해, 안좋게 생각하는 것일 수도 있다
parentTable_key
를 Column 에 가지고, Index 처럼 운용하던데.. 이것때문에 실상쿼리를 보면 계속해서 자식객체 INSERT 쿼리가 발사되고.. 쿼리적으로 효율적으로 바꿀까 하다가 2주라는 짧은 프로젝트니 최대한 DDD 를 경험해보자고 결심했다.
- 디온의 리뷰대로 새로운 방향성이니 하나의 컨셉으로서 공부해보는게 좋다고 생각했다.
- 중간에 CardRepository 를 만들까 생각했는데.. 그럼 Spring Data JDBC 를 사용하는 이유가 없고, 학습이 아닌.. 기능구현에 초점을 맞춘다고 생각해서 조원들간 처음에 약속했던대로 학습에 방향을 두는 것에 초점을 두었습니다.
내가 문제를 겪었던 점
- React 에서 CardComponent 의 ID 를 관리하기 위해서는 ResponseData 에 ID 를 넣어줄 필요가 있다. 하지만 DB 에 키를 위임하게 되면 Server-Side 에서도 DB 를 거치기 전까지는 ID property 를 알 수 있는 방법에 한정적이므로(Aggregate Root 에 의해 관리되는 경우), ID 값을 가지게 하기 위해서는 따라서 대표적으로 아래와 같이 크게 두가지 방법론이 존재한다고 생각한다.
1. 카드 추가 (POST) 요청을 보낸 뒤 Server-Side 에서 Redirection 응답을 줘서 다시 렌더링 한뒤 GET 요청으로 카드 데이터를 받는다.
- 1번 방식은 구현에는 쉬울 것이나, 문제는 Client 비 친화적일 수 있다는 것이다. 충분히 Axios 방식으로 동작할 수 있음에도, 이러한 방식을 선택하는 건 좋지 않다고 생각한다.
2. 카드 추가 (POST) 요청을 보낸 뒤 Server-Side 에서 CardID 를 담아준다.
- 사실 2번 방법도 AggregateRoot 방식으로 관리되지 않는 Entity 이여서 Repository 를 사용한다면 어려운 방식은 아니다. 하지만, 나는 Column 이라는 상위 연관관계에서 Card 를 관리하는 구조이므로, Repository 를 통한 ID 값을 추적해내는게 어려웠다. 따라서 인공키 구조를 가져보는 것은 어떨까? 라는 생각을 하게 되었고, 아래와 같이 코드로 구현하게 되었다.
UUID 구조의 인공키
- 이전에 Brian 의 Review 과정에서 UUID 를 주키로 사용했을때 장/단점을 살펴보았을때 대략적으로 검색을 통해 공부한 내용은 아래와 같았다.
- UUID 를 주키로 놓게 되면, 주키 INDEX 가 비대해질 수 있다. UUID 는 36자리의 랜덤 난수? 를 가지게 되는데 이는 정렬하는데 어려움을 겪을 수 있을만하다고 생각한다.
- 하지만 UUID 를 최적화된 형태로 변환하여 저장하면 효율적으로 사용이 가능하다고 보았던것 같다.
- Server-Side 에서도 객체의 Id 를 저장하고 있을 수 있다.
인공키의 사용
- 그래서 Entity 가 생성될때, 인공키를 사용하여 고유한 키값을 생성하고, 이를 Response 에 넣어 전달할 수 있도록 했다. 아래코드가 일단 UUID 를 생성하여 Entity 를 가지는 구조이다.
public Card(String title, String content, String author) {
this.id = UUID.randomUUID().toString();
this.title = title;
this.content = content;
this.author = author;
this.updateDateTime = LocalDateTime.now();
}
- 일단 위와 같은 설계로 Entity 생성간 Key 를 가질 수 있게 됬다. 따라서 ResponseEntity 에서 Key 를 줄 수 있게 되었다.
@PostMapping()
public ResponseEntity<?> addCard(@Validated @RequestBody Card card, @PathVariable Long id, BindingResult bindingResult) {
final Card saveCard = columnService.addCard(id, card);
return ResponseEntity.ok().body(new CardInfoData(id, saveCard.getId()));
}
Response
{
"columnId": 1,
"cardId": "6e90cef7-cabe-440b-99b0-c2ff289a2653"
}
DB 에서 UUID 는 ?
- 내 데이터베이스 에서는 아래와 같이 저장되어 지고 있다.
DB 테스트
- 백만건 기준으로 수행한다. (천만건 하다가 맥북 저세상으로 보내줄 뻔했다...)
- DB 의 제일 마지막 열에 있는 데이터를 가져올때 기준으로 수행해본다.
- 인공키 (UUID) VS 인공키 (Auto Increment)
- 내가 테스트를 해봤는데 천만건으로 한번 더 하면 맥북 맛탱이 갈거 같아서 1억건 정도로 하고싶은데.. 무리다 나중에 내 컴퓨터에서 해보고 여기 좋은 글이 있으니 다들 이걸 읽어보길 바란다.
- 백만건으로 해봤는데 차이가 없다. 아마 1억건 이상은 되야하지 않을까? 근데 알게된건 적은 양의 데이터라면 충분히 UUID 를 써도 별로 성능에 문제를 주지 못한다는 것이다.
- 그리고 효율적으로 저장하는 방법도 있으니 사실 써도 무방 할것 같다는 생각이 들었다.
- 왜 사람들이 싸우는지 알겠다 이제야, 성능상의 큰 문제가 대규모 기업아니면 발생할 것 같지 않다.
UUID VS AUTO GENERATED KEY
연관 글
파이썬을 이용한 bulkInsert
https://velog.io/@tmdgusya/DB-Bulk-insert