Archive/예전 TIL

JPA 쿼리를 활용한 성능 개선

khu2172 2025. 2. 18. 16:04

문제 상황: N+1 문제 발생 및 불필요한 쿼리 실행

- 기존 코드에서 워크스페이스와 멤버 정보를 조회할 때 불필요한 다중 쿼리가 실행되는 문제가 발생함.

- InviteRepository와 WorkspaceRepository에서 개별적으로 데이터를 조회하는 과정에서 N+1 문제가 발생하여 조회 성능이 저하됨.

 

1. 멤버 초대 조회 시 성능 개선 (InviteRepository)

수정 전

- 특정 워크스페이스에서 특정 유저들에게 보낸 초대 정보를 조회할 때, 개별적으로 유저를 조회하는 다중 쿼리가 실행됨.-

- 기존 방식에서는 findAll()을 호출한 후, 초대 대상자를 개별적으로 필터링하여 처리함.

- N+1 문제 발생: 초대된 멤버를 개별적으로 조회하는 추가 쿼리 실행됨.

 

수정 후

JPQL 쿼리에서 IN 조건을 활용하여 한 번의 쿼리로 여러 초대 정보를 조회

@Query("SELECT i FROM Invite i WHERE i.workspace.id = :workspaceId AND i.invitee.id IN :userIds") List<Invite> findByWorkspaceIdAndInviteeId(@Param("workspaceId") Long workspaceId, @Param("userIds") List<Long> userIds);

 

- IN 연산자를 활용하여 다중 유저에 대한 초대 정보를 한 번의 쿼리로 가져옴.

- 불필요한 개별 SELECT 쿼리 실행을 제거하여 쿼리 실행 횟수를 줄이고 성능을 최적화.

 

2. 워크스페이스의 멤버 정보 조회 성능 개선 (WorkspaceRepository)

수정 전

- 워크스페이스의 멤버 정보를 조회할 때, 워크스페이스를 가져온 후, 멤버 정보를 개별적으로 조회하는 추가 쿼리가 실행됨.

- N+1 문제 발생: findById(workspaceId) 호출 후, 관련 멤버 정보 조회 시 추가적인 SELECT 쿼리 실행.

 

수정 후

JPQL의 FETCH JOIN을 사용하여 워크스페이스와 멤버 정보를 한 번의 쿼리로 조회

@Query("SELECT w FROM Workspace w INNER JOIN FETCH w.members m WHERE w.id = :workspaceId") Workspace findMemberByWorkspaceId(@Param("workspaceId") Long workspaceId);

 

- INNER JOIN FETCH를 사용하여 워크스페이스와 멤버 정보를 한 번의 쿼리로 조회.

- Lazy Loading으로 인해 발생하는 추가적인 SELECT 쿼리 실행 방지.

- JOIN FETCH를 활용하여 연관된 엔티티를 즉시 로드하여 성능 최적화.

 

3. 특정 유저가 속한 워크스페이스 목록 조회 성능 개선 (WorkspaceRepository)

수정 전

- 특정 유저가 속한 워크스페이스 목록을 조회할 때, 'User → Member' 그리고 'Member → Workspace'
를 각각 조회하면서 여러 개의 SELECT 쿼리가 실행됨.

 

수정 후

JOIN을 활용하여 한 번의 쿼리로 워크스페이스 목록 조회

@Query("SELECT w FROM Workspace w INNER JOIN Member m ON m.workspace.id = w.id INNER JOIN User u ON u.id = m.user.id WHERE u.id = :userId") List<Workspace> findWorkspacesByUserId(@Param("userId") Long userId);

 

- INNER JOIN을 활용하여 User → Member → Workspace의 관계를 한 번의 쿼리로 조회.

- 기존보다 훨씬 빠르게 유저가 속한 워크스페이스 목록을 조회 가능.

- 쿼리 최적화로 DB 부하를 줄이고, 실행 속도를 개선.