프로젝트/RESTAPI 추천 서비스

어김없이 또 발생한 N+1 문제(요청 기록 조회 API)

indeep 2024. 4. 9. 00:51

관리자가 유저들의 요청 기록을 조회하는 API를 날리는데 쿼리가 이상하다.

현재 유저는 4명이 있고, 요청기록은 100만 개의 데이터가 존재.

Hibernate: 
    select
        arh1_0.id,
        arh1_0.member_id,
        arh1_0.method_type,
        arh1_0.request_content,
        arh1_0.request_date,
        arh1_0.request_status,
        arh1_0.response_content 
    from
        api_request_history arh1_0 
    order by
        arh1_0.request_date desc 
    limit
        ?, ?
Hibernate: 
    select
        m1_0.id,
        m1_0.create_date,
        m1_0.email,
        m1_0.login_last_date,
        m1_0.nickname,
        m1_0.password,
        m1_0.social_type,
        m1_0.token 
    from
        member m1_0 
    where
        m1_0.id=?
Hibernate: 
    select
        m1_0.id,
        m1_0.create_date,
        m1_0.email,
        m1_0.login_last_date,
        m1_0.nickname,
        m1_0.password,
        m1_0.social_type,
        m1_0.token 
    from
        member m1_0 
    where
        m1_0.id=?
Hibernate: 
    select
        m1_0.id,
        m1_0.create_date,
        m1_0.email,
        m1_0.login_last_date,
        m1_0.nickname,
        m1_0.password,
        m1_0.social_type,
        m1_0.token 
    from
        member m1_0 
    where
        m1_0.id=?
Hibernate: 
    select
        m1_0.id,
        m1_0.create_date,
        m1_0.email,
        m1_0.login_last_date,
        m1_0.nickname,
        m1_0.password,
        m1_0.social_type,
        m1_0.token 
    from
        member m1_0 
    where
        m1_0.id=?
Hibernate: 
    select
        count(arh1_0.id) 
    from
        api_request_history arh1_0
2024-04-09T00:43:18.496+09:00  INFO 9496 --- [restapi] [nio-8080-exec-1] c.p.r.d.a.s.impl.ApiRequestServiceImpl   : 쿼리 걸린 시간 : 510밀리초

보면 유저가 4명이라 유저 쿼리가 4개 날아간 것이 확인된다.

 

이제 생각해보니 QueryDSL로 변경하면서 fetchJoin을 적용을 안 했었네?

 

List<ApiRequestHistory> results = queryFactory                          
        .selectFrom(apiRequestHistory)                                        
        .orderBy(apiRequestHistory.requestDate.desc())                  
        .offset(pageable.getOffset())                                   
        .limit(pageable.getPageSize())                                  
        .fetch();

현재 쿼리를 보면 apiRequestHistory만 찾아오고 연관관계는 member에 대해서는 따로 조치를 안 취했다.

 

List<ApiRequestHistory> results = queryFactory                          
        .selectFrom(apiRequestHistory)                                  
        .leftJoin(apiRequestHistory.member, member).fetchJoin()         
        .orderBy(apiRequestHistory.requestDate.desc())                  
        .offset(pageable.getOffset())                                   
        .limit(pageable.getPageSize())                                  
        .fetch();

leftJoin으로 member를 조인시켜주고 이후 fetchJoin을 통해 포함시키게 만든다.

 

Hibernate: 
    select
        arh1_0.id,
        m1_0.id,
        m1_0.create_date,
        m1_0.email,
        m1_0.login_last_date,
        m1_0.nickname,
        m1_0.password,
        m1_0.social_type,
        m1_0.token,
        arh1_0.method_type,
        arh1_0.request_content,
        arh1_0.request_date,
        arh1_0.request_status,
        arh1_0.response_content 
    from
        api_request_history arh1_0 
    left join
        member m1_0 
            on m1_0.id=arh1_0.member_id 
    order by
        arh1_0.request_date desc 
    limit
        ?, ?
Hibernate: 
    select
        count(arh1_0.id) 
    from
        api_request_history arh1_0
2024-04-09T00:47:58.229+09:00  INFO 22044 --- [restapi] [nio-8080-exec-1] c.p.r.d.a.s.impl.ApiRequestServiceImpl   : 쿼리 걸린 시간 : 537밀리초

그러면 한번에 가져오는 걸 확인할 수 있다.

 

문제는 100만개 데이터 조회하는데 0.5초가 걸리는데 이거 뭔가 줄일 수 있으려나??

반응형