[Outstagram] DB 쿼리 최적화

nick·2024년 4월 24일
0

Outstagram

목록 보기
3/14

현재 상황

  • '나의 게시물' 조회 기능을 구현할 때, 내가 작성한 게시물과 각 게시물의 대표 이미지 1개씩 내려주도록 개발하고 싶음

초기 구현

구현 방식

  1. 우선 내가 작성한 모든 게시물을 가져오고

  2. 각 게시물을 순회하면서 대표 이미지 1개씩 가져옴

결과

image

DEBUG c.o.o.mapper.PostMapper.findByUserId - ==>  Preparing: SELECT id, contents, likes FROM post WHERE user_id = ? AND is_deleted = 0 ORDER BY create_date DESC
DEBUG c.o.o.mapper.PostMapper.findByUserId - ==> Parameters: 4(Long)
TRACE c.o.o.mapper.PostMapper.findByUserId - <==    Columns: id, contents, likes
TRACE c.o.o.mapper.PostMapper.findByUserId - <==        Row: 12, <<BLOB>>, 0
TRACE c.o.o.mapper.PostMapper.findByUserId - <==        Row: 11, <<BLOB>>, 0
TRACE c.o.o.mapper.PostMapper.findByUserId - <==        Row: 10, <<BLOB>>, 0
DEBUG c.o.o.mapper.PostMapper.findByUserId - <==      Total: 3
DEBUG c.o.o.m.I.findFirstByPostId - ==>  Preparing: SELECT id, img_path, saved_img_name FROM image WHERE post_id = ? AND is_deleted = 0 ORDER BY id LIMIT 1
DEBUG c.o.o.m.I.findFirstByPostId - ==> Parameters: 12(Long)
TRACE c.o.o.m.I.findFirstByPostId - <==    Columns: id, img_path, saved_img_name
TRACE c.o.o.m.I.findFirstByPostId - <==        Row: 8, C:\Users\Administrator\Desktop\outstagram\com.outstagram.upload.path, 379c1e02-067d-4ed6-9843-5d347a32f3d6_MySQL_수료증.pdf
DEBUG c.o.o.m.I.findFirstByPostId - <==      Total: 1
DEBUG c.o.o.m.I.findFirstByPostId - ==>  Preparing: SELECT id, img_path, saved_img_name FROM image WHERE post_id = ? AND is_deleted = 0 ORDER BY id LIMIT 1
DEBUG c.o.o.m.I.findFirstByPostId - ==> Parameters: 11(Long)
TRACE c.o.o.m.I.findFirstByPostId - <==    Columns: id, img_path, saved_img_name
TRACE c.o.o.m.I.findFirstByPostId - <==        Row: 6, C:\Users\Administrator\Desktop\outstagram\com.outstagram.upload.path, 56ac1897-d629-4363-aa89-ff1ab2d20001_수상확인서_2023-2학기 아주톤_최우수상(조익현).pdf
DEBUG c.o.o.m.I.findFirstByPostId - <==      Total: 1
DEBUG c.o.o.m.I.findFirstByPostId - ==>  Preparing: SELECT id, img_path, saved_img_name FROM image WHERE post_id = ? AND is_deleted = 0 ORDER BY id LIMIT 1
DEBUG c.o.o.m.I.findFirstByPostId - ==> Parameters: 10(Long)
TRACE c.o.o.m.I.findFirstByPostId - <==    Columns: id, img_path, saved_img_name
TRACE c.o.o.m.I.findFirstByPostId - <==        Row: 5, C:\Users\Administrator\Desktop\outstagram\com.outstagram.upload.path, 685b54ef-5e25-4b8f-9768-e7dd2a7833ff_HTTP 수료증.pdf
DEBUG c.o.o.m.I.findFirstByPostId - <==      Total: 1
  • 게시물 목록 조회 쿼리 1번(게시물 3개), 각 게시물 당 이미지 조회 쿼리 3번 => 총 4번의 쿼리가 발생

  • 응답 시간 약 32ms 발생

📌 문제점

  • 만약 게시물이 100개라면, 각 게시물의 대표 이미지 조회하기 위해서 이미지 조회 쿼리가 100개 날라감

  • N+1의 문제와 유사하다 (엄연히 말하면 N+1 문제랑 다르지만, 유사한 결과가 나와서 이렇게 설명함..)


리팩토링 후

구현 방식

  • postimage를 조인한 후, imageid 값을 오름차순으로 정렬한 후 제일 첫 번째 이미지 가져오기

결과

image

17:12:21.726 [http-nio-8080-exec-4] INFO  c.o.o.c.filter.LoggingInterceptor - REQUEST [604aa914-7a0d-4be0-b7ba-e14434207427][/api/posts/][com.outstagram.outstagram.controller.PostController#getMyPosts(UserDTO)]
17:12:21.726 [http-nio-8080-exec-4] INFO  c.o.o.c.filter.LoginCheckInterceptor - 인증 체크 인터셉터 실행 /api/posts/
17:12:21.727 [http-nio-8080-exec-4] INFO  c.o.o.common.aop.LoginAspect - AOP - @Login Check Started
17:12:21.727 [http-nio-8080-exec-4] DEBUG c.o.o.m.P.findWithImageByUserId - ==>  Preparing: SELECT p.id AS post_id, p.contents, p.likes, i.id AS image_id, i.img_path, i.saved_img_name FROM post AS p JOIN image AS i ON p.id = i.post_id WHERE p.user_id = ? AND p.is_deleted = 0 AND i.is_deleted = 0 AND i.id IN ( SELECT MIN(id) FROM image WHERE is_deleted = 0 GROUP BY post_id ) ORDER BY p.create_date DESC
17:12:21.728 [http-nio-8080-exec-4] DEBUG c.o.o.m.P.findWithImageByUserId - ==> Parameters: 4(Long)
17:12:21.729 [http-nio-8080-exec-4] TRACE c.o.o.m.P.findWithImageByUserId - <==    Columns: post_id, contents, likes, image_id, img_path, saved_img_name
17:12:21.729 [http-nio-8080-exec-4] TRACE c.o.o.m.P.findWithImageByUserId - <==        Row: 12, <<BLOB>>, 0, 8, C:\Users\Administrator\Desktop\outstagram\com.outstagram.upload.path, 379c1e02-067d-4ed6-9843-5d347a32f3d6_MySQL_수료증.pdf
17:12:21.729 [http-nio-8080-exec-4] TRACE c.o.o.m.P.findWithImageByUserId - <==        Row: 11, <<BLOB>>, 0, 6, C:\Users\Administrator\Desktop\outstagram\com.outstagram.upload.path, 56ac1897-d629-4363-aa89-ff1ab2d20001_수상확인서_2023-2학기 아주톤_최우수상(조익현).pdf
17:12:21.730 [http-nio-8080-exec-4] TRACE c.o.o.m.P.findWithImageByUserId - <==        Row: 10, <<BLOB>>, 0, 5, C:\Users\Administrator\Desktop\outstagram\com.outstagram.upload.path, 685b54ef-5e25-4b8f-9768-e7dd2a7833ff_HTTP 수료증.pdf
17:12:21.730 [http-nio-8080-exec-4] DEBUG c.o.o.m.P.findWithImageByUserId - <==      Total: 3
17:12:21.735 [http-nio-8080-exec-4] INFO  c.o.o.c.filter.LoggingInterceptor - RESPONSE [604aa914-7a0d-4be0-b7ba-e14434207427][/api/posts/]
  • 게시물과 이미지 테이블을 조인해서 가져오는 쿼리 1개만 발생

  • 응답 시간도 13ms


⭐ 결론

  • 게시물이 3개일 때도, 32ms -> 13ms로 성능 차이가 눈에 띄게 발생

  • 게시물과 이미지 개수가 늘어날수록 성능 차이는 더 벌어질 것으로 예상된다

  • 추후에 성능 테스트로 증명?해보기

  • 최대한 쿼리의 개수가 덜 발생하도록 개발하면 성능 이득을 많이 볼 수 있을 것 같음

profile
티스토리로 이전 : https://andantej99.tistory.com/

0개의 댓글