-
Spring Db, jpa 를 사용하며 고민들project 2022. 3. 29. 12:48
웹 프로젝트를 하면서 Spring Data Jpa 를 사용했다. 고민했던 부분들을 적어두려고 한다.
0. 쿼리 최적화
크게 두 가지 관심사가 있을 것 같다. (1) 쿼리가 몇 번 나가는지 (2) 쿼리 실행 속도가 어떤지
프로젝트 에서는 1번 위주로 고민했다. Spring + jpa 모두 처음 프로젝트에 활용하는 거다 보니 숙련도 부족으로 인한 불필요한 쿼리가 나갔기 때문이다.
간단하게 확인하려면 intellij 로그에서 확인하면 되고, 정확한 것은 mariadb 로그를 찍어서 확인하면 된다. Intellij 로그, 즉 jpa 로그와 mariadb 로그가 다른 경우가 있고 이는 jpa 오류로 보인다.
* 쿼리 로그가 정말 중요하다. 데이터베이스 콘솔 등에서 찍어주는 실제 로그를 보지 않는 이상, 블랙박스로 개발하는 거나 마찬가지다. 꼭 기억하자 뭘하던 로그를 보는거다.
1. Entity 조회 방식의 최적화
이건 간단하게 인프런 인강(김영한님)을 참고해서 ManyToOne, OneToOne 은 fetch join 으로, OneToMany 는 Hibernate batch 로 해결했다.
서비스 단에서 파라미터를 Entity 로 받을지, id 로 받을지 팀원과 고민한 적이 있었다. 지금 생각은, 둘 중 하나 선택으로 불필요한 쿼리가 나가지 않도록 하는 것이다. 필요하다면 Entity 를 fetch join 해서 넘겨주는게 좋다. Fetch join 을 안하고 넘겨주었다가 쿼리가 두 방 나가는 수가 있다.
-> 트랜잭션을 고려해야 한다. Persistence context 에서 관리하는 객체인지 여부도 고려해야 하고 @Transactional 로 추상화된 부분을 고려해서 문제 없이 코드를 짜야 한다.
2. Identity vs. Sequence
먼저, 프로젝트에서 사용한 MariaDb 는 default 가 sequence 방식이다. 약속을 auto 로 사용하기로 했었고 지금 와서 보니까 sequence 는 select nextval(hibernate_sequence) 쿼리가 추가로 나간다. Sequence 방식이 Identity 보다 성능적으로 안좋다는 글이 많이 있었는데 이것 때문인 것 같다. 운영 데이터가 생긴 이후에 바꾸었을 때 어떤 효과가 날 지 몰라서 바꾸기 어려웠다.
사실 identity 로 할 지, sequence 로 할 지는 프로젝트 초반에 팀원과 고민했던 부분이다. 크게 고민하지 않고 적당히 auto 로 하자고 결정했던 것 같다. 지나고 보니 결국 그 때 정확하게 고민하고 정했어야 하는 것 같다. 데이터베이스는 설계할 때 많이 고민하고 해야 하는 것 같다.
* 무언가 선택을 할 때 항상 팀원과 같이 고민하고 장단점을 따져보고 해야 한다..!
3. Batch insert
예를 들어 for loop 를 돌면서 엔티티를 insert하는 경우이다. for 을 그대로 두고 최적화할수도 있고 for 을 없애고 쿼리를 짜서 해결할 수 있다.
이 부분을 구현하다가, jpa 가 모든걸 다 해주진 않는다는 생각이 들었다. Hibernate batch 를 사용하면 많은 경우에 batch insert 최적화가 가능하겠지만, 어느 경우엔 불가능하다.
Jpa 로 해결 가능한 경우엔 정말 application.properties 에 한 줄 추가하면 모든게 해결되서 편하다. 그렇지 않은 경우엔 Jdbc 로 sql 을 직접 짜는게 좋다고 생각한다.
또한 space vs time trade-off 이다. 메모리에 쌓아두었다가 모이면 쿼리를 날려서 성능적 이점을 얻지만, 메모리를 차지한다는 단점이 있다.
Generated startegy 가 identity / auto 인 경우 batch insert 최적화가 불가능하다고 한다. Jdbc template 을 활용해서 이 부분을 작성할 수 있다.
4. Redis
(이건 jpa 랑 상관없긴 한데.. db 긴 하니까..)레디스.. 인메모리 저장소이며 데이터베이스고 껐다 켰을 때 데이터가 살아있을 확률이 높다.(not gauranteed) 네트워크 통신을 해서 톰캣 프로세스랑 라이프사이클이 다르다. 즉, 데이터의 삶이 인메모리도 아니고 데이터베이스도 아니라서 주의해서 써야 한다!!
예를 들어 로그아웃 블랙리스트를 구현할 때 쓸 수 있다. 서버로의 모든 요청에 한번씩 조회해야 하므로 in-memory 수준으로 해야 하고, 껐다 켰을 때 로그아웃 했는데 로그인이 되있는 경우가 있으면 안되므로 데이터베이스의 성질도 갖추어야 한다. 또, access token 이 만료되면 필요없어지므로 일정 시간이 지나면 없어지도록 해야 한다.
5. Spring data jpa 한계?
Spring data jpa 를 써서 Party 를 조회할 때 findByMemberId 메소드를 호출하면 left out join 이 발생한다. 테이블로 생각하면 join 필요 없이 foreign key 로 조회하면 되는데. 왜지?? Id 가 fk 가 아닐 때랑 똑같이 조회해서 그런거 같은데 왜 최적화가 안된걸까?
이런 부분은 그냥 jpql 이나 querydsl 로 짜면 되지만 프레임워크가 작동하는 방식이 왠지 궁금해진다.
'project' 카테고리의 다른 글
테스트 코드의 중요성, TDD (0) 2022.04.30 Spring security > 5.1 jwt 인증하는 방법 (0) 2022.04.25 spring security oauth2 로그인 구현 (개발 로그) (0) 2022.03.30 협업 준비 (백엔드, 인프라) (0) 2022.02.02 게시판 프로젝트 vue.js + java spring boot (일기장) (0) 2022.01.11