N+1문제 해결하기

송민지·2025년 6월 27일
0

PortCoin

목록 보기
7/7

문제 - N+1 발생

hibernate를 통해 콘솔에 출력되는 SQL을 보며 이상한 쿼리를 출력하는 API를 발견하였습니다.

select
        p1_0.portfolio_id,
        p1_0.created_at,
        p1_0.deleted_at,
        p1_0.name,
        p1_0.updated_at,
        p1_0.user_id 
    from
        portfolio p1_0 
    where
        p1_0.portfolio_id=?
2025-06-27T10:05:06.383+09:00 DEBUG 6750 --- [nio-8080-exec-1] org.hibernate.SQL                        : 
    select
        pc1_0.portfolio_id,
        pc1_0.id,
        pc1_0.amount,
        pc1_0.coin_id,
        pc1_0.created_at,
        pc1_0.current_price,
        pc1_0.purchase_date,
        pc1_0.purchase_price,
        pc1_0.updated_at 
    from
        portfolio_coin pc1_0 
    where
        pc1_0.portfolio_id=?
2025-06-27T10:05:06.390+09:00 DEBUG 6750 --- [nio-8080-exec-1] org.hibernate.SQL                        : 
    select
        c1_0.id,
        c1_0.created_at,
        c1_0.name,
        c1_0.symbol,
        c1_0.updated_at 
    from
        coin c1_0 
    where
        c1_0.id=?
2025-06-27T10:05:06.392+09:00 DEBUG 6750 --- [nio-8080-exec-1] org.hibernate.SQL                        : 
    select
        c1_0.id,
        c1_0.created_at,
        c1_0.name,
        c1_0.symbol,
        c1_0.updated_at 
    from
        coin c1_0 
    where
        c1_0.id=?
2025-06-27T10:05:06.394+09:00 DEBUG 6750 --- [nio-8080-exec-1] org.hibernate.SQL                        : 
    select
        c1_0.id,
        c1_0.created_at,
        c1_0.name,
        c1_0.symbol,
        c1_0.updated_at 
    from
        coin c1_0 
    where
        c1_0.id=?

포트폴리오 상세보기 API였는데, 현재 포트폴리오에 등록된 코인이 3개를 불러오기 위해 coin에 관련된 쿼리만 3개가 생성되고 있었습니다.

해결과정

PortfolioCoin entitydp BatchSize 설정과 application-dev.yml에 defatult batch size를 설정해봤지만, 모두 실패하였습니다.

JPQL에서 fetch join을 이용하여 해결하였습니다.

해결

 select
        p1_0.portfolio_id,
        p1_0.created_at,
        p1_0.deleted_at,
        p1_0.name,
        pc1_0.portfolio_id,
        pc1_0.id,
        pc1_0.amount,
        c1_0.id,
        c1_0.created_at,
        c1_0.name,
        c1_0.symbol,
        c1_0.updated_at,
        pc1_0.created_at,
        pc1_0.current_price,
        pc1_0.purchase_date,
        pc1_0.purchase_price,
        pc1_0.updated_at,
        p1_0.updated_at,
        p1_0.user_id 
    from
        portfolio p1_0 
    left join
        portfolio_coin pc1_0 
            on p1_0.portfolio_id=pc1_0.portfolio_id 
    left join
        coin c1_0 
            on c1_0.id=pc1_0.coin_id 
    where
        p1_0.portfolio_id=?

Portfolio 엔티티는 PortfolioCoin 엔티티와 1:N 관계를, PortfolioCoin 엔티티는 Coin 엔티티와 N:1 관계를 가지고 있습니다.
따라서 portfolioId로 Portfolio를 조회할 때, 연관된 PortfolioCoins를 LEFT FETCH JOIN으로 가져오고,
이어서 각 PortfolioCoin과 연결된 Coin 역시 LEFT FETCH JOIN을 사용해 함께 조회하였습니다.

profile
항상 밝게

0개의 댓글