문의 조회 성능 개선

naruddl·2024년 10월 27일

테스트 환경 세팅

한 게시글에 문의 데이터 500개

한 문의에 대해 답변 1개


성능 개선 전

SELECT문 - 10번 발생

1.
    select
        q1_0.idx,
        q1_0.answer_status,
        q1_0.content,
        q1_0.created_at,
        q1_0.modified_at,
        q1_0.product_board_idx,
        q1_0.title,
        q1_0.user_idx 
    from
        question q1_0 
    where
        q1_0.product_board_idx=? 
    order by
        q1_0.created_at desc limit ?,
        ?
        
2.
    select
        count(q1_0.idx) 
    from
        question q1_0 
    where
        q1_0.product_board_idx=?

3.
    select
        a1_0.question_idx,
        a1_0.idx,
        a1_0.company_idx,
        a1_0.content,
        a1_0.created_at 
    from
        answer a1_0 
    where
        a1_0.question_idx=?

4.
    select
        c1_0.idx,
        c1_0.company_name,
        c1_0.email 
    from
        company c1_0 
    where
        c1_0.idx=?

5.
    select
        u1_0.idx,
        u1_0.email,
        u1_0.name 
    from
        user u1_0 
    where
        u1_0.idx=?

6.
    select
        p1_0.idx,
        p1_0.category_idx,
        p1_0.company_idx,
        p1_0.created_at,
        p1_0.discount_rate,
        p1_0.ended_at,
        p1_0.minimum_price,
        p1_0.modified_at,
        p1_0.product_detail_url,
        p1_0.product_thumbnail_url,
        p1_0.started_at,
        p1_0.status,
        p1_0.title 
    from
        product_board p1_0 
    where
        p1_0.idx=?

7.
    select
        a1_0.question_idx,
        a1_0.idx,
        a1_0.company_idx,
        a1_0.content,
        a1_0.created_at 
    from
        answer a1_0 
    where
        a1_0.question_idx=?

8.
    select
        a1_0.question_idx,
        a1_0.idx,
        a1_0.company_idx,
        a1_0.content,
        a1_0.created_at 
    from
        answer a1_0 
    where
        a1_0.question_idx=?

9.
    select
        a1_0.question_idx,
        a1_0.idx,
        a1_0.company_idx,
        a1_0.content,
        a1_0.created_at 
    from
        answer a1_0 
    where
        a1_0.question_idx=?

10.
    select
        a1_0.question_idx,
        a1_0.idx,
        a1_0.company_idx,
        a1_0.content,
        a1_0.created_at 
    from
        answer a1_0 
    where
        a1_0.question_idx=?
  1. 문의 목록 조회 (1회 SELECT)
    • 특정 product_board_idx의 문의 목록을 최신 순으로 조회
  2. 문의 개수 조회 (1회 SELECT)
    • 페이징 처리를 위한 문의 수 계산
  3. 답변 조회 (5회 SELECT - N+1 문제)
    • 각 문의에 대한 Answer 데이터를 개별적으로 조회
  4. 판매자 정보 조회 (1회 SELECT)
    • 답변을 작성한 판매자의 정보 조회
  5. 문의 작성자 정보 조회 (1회 SELECT)
    • 각 문의 작성자의 이메일 및 이름 정보 조회
  6. 상품 정보 조회 (1회 SELECT)
    • 문의와 연결된 ProductBoard 정보 조회

➡️ 총 10회의 SELECT문 발생

각 문의에 대해 개별적으로 답변을 조회하고, 판매자 정보, 작성자 정보, 상품 정보를 따로 조회하면서 중복된 쿼리 호출이 발생했습니다. 그 결과, 총 10번의 SELECT문이 실행되어 데이터베이스에 불필요한 부하를 줌.

응답시간 테스트

→ 평균 응답 시간 20.65(ms)


성능 개선

  1. 답변 조회 최적화: @BatchSize를 적용하여, QuestionAnswer 간의 지연 로딩 문제를 개선했습니다. 기존에는 각 문의마다 답변을 개별적으로 조회해 N+1 문제가 발생했지만, 이제는 한 번에 최대 5개의 답변을 가져오도록 변경해 쿼리 호출 수를 줄였습니다.
  2. 상품 정보 조회 개선: QuestionRepository에서 JOIN FETCH를 사용해 QuestionProductBoard를 한 번에 조회하도록 쿼리를 수정했습니다. 이전에는 지연 로딩으로 인해 상품 정보를 추가로 불러오는 쿼리가 발생했지만, 이제는 두 데이터를 함께 가져와 불필요한 쿼리 호출을 줄였습니다.

성능 개선 후

SELECT문 - 5번 발생

1.
    select
        q1_0.idx,
        q1_0.answer_status,
        q1_0.content,
        q1_0.created_at,
        q1_0.modified_at,
        p1_0.idx,
        p1_0.category_idx,
        p1_0.company_idx,
        p1_0.created_at,
        p1_0.discount_rate,
        p1_0.ended_at,
        p1_0.minimum_price,
        p1_0.modified_at,
        p1_0.product_detail_url,
        p1_0.product_thumbnail_url,
        p1_0.started_at,
        p1_0.status,
        p1_0.title,
        q1_0.title,
        q1_0.user_idx 
    from
        question q1_0 
    join
        product_board p1_0 
            on p1_0.idx=q1_0.product_board_idx 
    where
        q1_0.product_board_idx=? 
    order by
        q1_0.created_at desc limit ?,
        ?

2.
    select
        count(q1_0.idx) 
    from
        question q1_0 
    join
        product_board p1_0 
            on p1_0.idx=q1_0.product_board_idx 
    where
        q1_0.product_board_idx=?

3.
    select
        a1_0.question_idx,
        a1_0.idx,
        a1_0.company_idx,
        a1_0.content,
        a1_0.created_at 
    from
        answer a1_0 
    where
        a1_0.question_idx in (?,?,?,?,?)

4.
    select
        c1_0.idx,
        c1_0.company_name,
        c1_0.email 
    from
        company c1_0 
    where
        c1_0.idx=?
        
5.
    select
        u1_0.idx,
        u1_0.email,
        u1_0.name 
    from
        user u1_0 
    where
        u1_0.idx=?
  1. 문의 목록 조회 (1회 SELECT)
    • 문의와 상품 정보를 JOIN FETCH로 한 번에 조회
  2. 문의 개수 조회 (1회 SELECT)
    • 페이징 처리를 위한 문의 수 계산
  3. 답변 조회 및 판매자 정보 조회 (2회 SELECT)
    • @BatchSize 적용으로 각 문의에 대한 답변을 묶어서 조회 (IN 사용)
    • 답변 작성자의 판매자 정보 조회
  4. 문의 작성자 정보 조회 (1회 SELECT)
    • 문의 작성자의 이메일 및 이름 정보 조회

➡️ 총 5회의 SELECT문 발생

응답 시간 테스트

→ 평균 응답 시간 13.95(ms)


결과

1. SELECT 쿼리 호출 횟수가 10번에서 5번으로 감소SELECT문은 5회 감소

  • 데이터베이스 부하가 줄어듦.
  • 쿼리 횟수를 50% 줄여, 데이터베이스 처리 성능을 향상시킴.
  • 불필요한 쿼리 5개를 제거하여 더 빠른 데이터 조회가 가능해짐.

2. 약 33%의 응답 속도 향상이 이루어짐.

개선 전개선 후
129 ms25 ms
229 ms21 ms
316 ms18 ms
421 ms10 ms
531 ms16 ms
620 ms12 ms
723 ms20 ms
815 ms12 ms
920 ms14 ms
1028 ms7 ms
1123 ms15 ms
1224 ms14 ms
1314 ms12 ms
1423 ms9 ms
158 ms19 ms
1619 ms16 ms
1717 ms6 ms
1817 ms20 ms
1920 ms6 ms
2016 ms7 ms
평균20.65 ms13.95 ms
profile
아자!아자! 개발자!

0개의 댓글