수행시간을 측정해보자.
1. EAGER 일 때 + findBy 메소드 그대로 활용
쿼리는 조인 없이
총 3개의 쿼리가 수행되고,
수행 시간: 34ms
2. 1번의 케이스에서 fetchType이 LAZY로 바꾼다면
쿼리는 변하지 않는다.
쿼리가 수행되는 시점만 바뀐다.
수행 시간: 35ms
3. UserEntity 참조 없이, CouponEntity만 바로 가져오게 변경
쿼리는 1번만 수행되고 usercoupon이랑 coupon이랑 조인된다.
수행 시간: 12ms
분석 결과 :
기존의 UserCouponEntity에서 findBy메소드로 자식 엔테디 CouponEntity, UserEntity를
자동으로 가져오는 LAZY EAGER 방식은 모두 JOIN 연산 없이 쿼리가 3번 일어나고,
UserCouponEntity에서 UserCouponEntity만 가져오는
@Query 개선된 쿼리는 JOIN(UserCouponEntity 조인 CouponEntity)을 통해서 1번의 쿼리만 수행된다.
테이블의 데이터 개수가 적으므로 조인의 영향은 거의 없고,
쿼리 수행 횟수만큼 시간이 늘어나는 것을 확인할 수 있다.
따라서 개선된 방식은 시행시간은 약 3배 줄었다.
테이블에 데이터 개수가 늘어나면 JOIN 비용이 급격하게 증가하므로,
데이터 개수가 많을 때, 결과가 달라질 수 있다.
아니면 조인을 안하면서, UserEntity에 대한 쿼리는 수행되지 않도록 더 나은 방법이 있는지 생각해보자.
1번과 2번에서 ManyToOne JoinColmn에서 조인이 수행되지 않고
쿼리의 개수만 늘어나는 것을 알 수 있다.
따라서, LAZY로 그대로 두고 Controller에서 Return할 때,
UserEntity는 참조하지 않으면서 CouponDTO의 목록만 뽑으면 될 것이다.
이렇게 하면 JOIN 없이 2번의 쿼리로 단축된다.
데이터가 많으면 JOIN을 안하고 2번의 쿼리가 더 나을 수도 있다.
수행 시간: 23ms
결론은
EAGER | LAZY | @Query | LAZY+UserEntity 참조 X | ||
조인 유무 | X | X | O | X | |
수행시간 | 34ms | 35ms | 12ms | 23ms | |
쿼리 개수 | 3 | 3 | 1 | 2 | |
데이터 양이 많아지면 | ? | ? | ? | ? |