-
Notifications
You must be signed in to change notification settings - Fork 8
쿼리 성능 개선 ‐ 태그 조회
데이터 스펙
멤버: 10 건
카테고리: 100 건 (멤버 당 10 건)
태그: 2000 건 (멤버 당 200 건)
템플릿: 10만 건 (멤버 당 1만 건)
소스 코드: 10만 ~ 50만 건 (템플릿 당 1~5 개 랜덤 생성)
테스트 조건
10개의 스레드로 100번씩 실행
총 1000번의 요청 실행
생성하는 템플릿 조건
사용하는 태그 : 20개 (모두 존재하는 태그 사용) 소스 코드 : 2개
Total request count: 1000
Total elapsed time: 5268308ms
Average elapsed time: 5268ms
총 [2 + 태그 개수] 개 쿼리 실행
-
Repository:
TemplateJpaRepository
-
Method:
findByMemberId
select
t1_0.id,
t1_0.category_id,
t1_0.created_at,
t1_0.description,
(select
count(*)
from
likes
where
likes.template_id = t1_0.id),
t1_0.member_id,
t1_0.modified_at,
t1_0.title
from
template t1_0
where
t1_0.member_id=?
- 호출 횟수: 1회
-
Repository:
TemplateTagJpaRepository
-
Method:
findDistinctByTemplateIn
select
distinct tt1_0.tag_id
from
template_tag tt1_0
where
tt1_0.template_id in (?, ?, ?, ?) # 템플릿 개수 만큼
- 호출 횟수: 1회
-
Repository:
TagJpaRepository
-
Method:
fetchById
select
t1_0.id,
t1_0.created_at,
t1_0.modified_at,
t1_0.name
from
tag t1_0
where
t1_0.id=?
- 호출 횟수: 200회 (태그 횟수 만큼)
커버링 인덱스 (Covering Index 혹은 Covered Index)
- 쿼리를 충족시키는 데 필요한 모든 데이터를 갖고 있는 인덱스
- SELECT, WHERE, ORDER BY, GROUP BY 등에 사용되는 모든 컬럼이 인덱스의 구성요소인 경우
멤버 ID로 해당 멤버의 모든 템플릿을 조회하는 로직이 존재한다.
하지만 실상 해당 로직 이후 template의 id외에는 사용되는 정보가 없다.
그래서 템플릿을 조회하는 로직을 템플릿 아이디를 조회하는 로직으로 수정한다.
이를 통해 커버링 인덱스 이용하도록 변경해 쿼리 성능을 개선한다.
@Query("""
SELECT t.id
FROM Template t
WHERE t.member.id = :memberId
""")
List<Long> findAllIdsByMemberId(Long memberId);
방대한 데이터 세트를 다룰 경우, IN 절은 성능 저하를 초래할 수 있다. 우리 코드에서 템플릿 태그를 조회하는 로직에는 템플릿 수의 데이터 세트가 IN 절에 존재한다. (지금은 10만개)
서브쿼리 사용으로 개선한다.
서브쿼리를 사용하면 IN 절의 성능을 향상시킬 수 있다. 서브쿼리는 메인 쿼리 내에 포함된 쿼리로, 동적으로 데이터를 조회하는 데 유용하다.
서브쿼리를 이용해 동적으로 데이터를 필터링하면 인덱스가 있는 열에서 동적으로 데이터를 조회할 수 있어서 효율적으로 필터링 할 수 있다.
서브쿼리를 이용하여 멤버 아이디로 템플릿 아이디를 조회하는 로직과 템플릿 태그를 조회하는 로직을 합쳐 IN 절 성능이 향상된다.
템플릿 태그에서 템플릿과 관련된 태그를 조회 한 후 태그 테이블을 하나하나 조회했다. 그래서 태그 조회 로직이 태그 개수만큼 실행되었다.
해당 문제를 해결하기 위해 템플릿 태그를 조회하는 로직과 태그를 조회하는 로직을 합쳤다.
@Query("""
SELECT DISTINCT t
FROM Tag t
WHERE t.id IN (
SELECT DISTINCT tt.id.tagId
FROM TemplateTag tt
WHERE tt.id.templateId IN
(SELECT te.id FROM Template te WHERE te.member.id = :memberId)
)
""")
List<Tag> findDistinctTagNameByMemberIdIn(Long memberId);
Total request count: 1000
Total elapsed time: 3632279ms
Average elapsed time: 3632ms
Total request count: 1000
Total elapsed time: 2704116ms
Average elapsed time: 2704ms
Total request count: 1000
Total elapsed time: 92743ms
Average elapsed time: 92ms
총 1개 쿼리 실행
-
Repository:
TemplateTagJpaRepository
-
Method:
findDistinctTagNameByMemberIdIn
select
distinct t1_0.id,
t1_0.created_at,
t1_0.modified_at,
t1_0.name
from
tag t1_0
where
t1_0.id in (select
distinct tt1_0.tag_id
from
template_tag tt1_0
where
tt1_0.template_id in (select
t2_0.id
from
template t2_0
where
t2_0.member_id=?))
- 호출 횟수: 1회
Total request count: 1000
Total elapsed time: 5268308ms
Average elapsed time: 5268ms
Total request count: 1000
Total elapsed time: 92743ms
Average elapsed time: 92ms
- 백엔드 코드 컨벤션
- 백엔드 기술 스택 및 선정 이유
- 각종 인스턴스 설정 파일 및 구성 위치 가이드
- ERD (24.09.27)
- 백엔드 CI CD 동작 프로세스
- 로컬 DB 환경 설정
- 백엔드 로깅 전략
- 백엔드 로그 모니터링 구성도
- 스프링 메트릭 모니터링 구성도
- Flyway 로 스키마 관리
- 코드잽 서버 구성도
- Git Submodule 사용 메뉴얼
- 프론트엔드 코드 컨벤션
- 프론트엔드 기술 스택 및 선정 이유
- 프론트엔드 서비스 타겟 환경 및 브라우저 지원 범위 선정
- 프론트엔드 모니터링 및 디버깅 환경 구축
- 프론트엔드 테스트 목록
- 프론트엔드 라이브러리 기술 검토
- 프론트엔드 개발서버, 운영서버 빌드 및 배포 환경 구분
- 목표했던 타겟 환경과 디바이스에서 서비스 핵심 기능 동작 확인
- 프론트엔드 접근성 개선 보고서
- EC2 로그 확인 방법
- VSCode를 통한 EC2 인스턴스 SSH 연결 방법
- 터미널을 통한 EC2 인스턴스 SSH 연결 방법
- NGINX 설정 파일 접근 및 적용 방법
- DB 접속 및 백업 방법
- [QA] 배포 전 체크리스트
- CI 파이프라인 구축
- CD 파이프라인 구축
- 백엔드 CI CD 트러블슈팅
- Lombok Annotation Processor 의존성을 추가한 이유
- 2차 스프린트 기준 ERD
- DTO 검증하기
- ProblemDetail
- Fork된 레포지토리 PR에서 CI Secrets 접근 문제 해결
- AWS CloudWatch 모니터링
- 스프링 메트릭 모니터링 구축 방법
- 로깅과 Logback에 대해 알아보아요.
- 백엔드 CD 파이프라인 Ver.2
- 요청, 응답 로그에 correlationId 를 추가하자!
- 3차 스프린트 기준 ERD
- 더미데이터 생성하고 실행하기
- 쿼리 성능 개선 결과
- 테이블별 인덱스 설정 목록
- 사용자 증가 시 발생할 수 있는 문제 상황과 개선 방안
- k6를 사용한 서버 부하 테스트
- 6차 스프린트 기준 ERD
- Query Performance Improvement Results
- 테스트 전략 및 CI 설정
- CI CD 구조
- 배포 전, 로컬에서 로그인 기능 포함 테스트해보는 법
- stylelint 적용기
- 내 작업 브랜치 중간에 Merge된 동료의 작업물을 넣고 싶다면 pull vs rebase
- [TS] Webpack config
- [TS] Webpack 환경에서 MSW v2 이슈
- [TS] webpack에서 react‐router‐dom 적용 안됨
- 2024.07.28 새 기획 회의
- 2024.07.26 2차 데모데이 후 회의
- 2024.07.11 백엔드 논의 좀 할게요
- 2024.07.11 백엔드 ERD 회의
- 2024.07.09 깃 브랜치 전략, PR 템플릿 회의
- 2024.07.03 주제 선정 회의
- 2023.07.03 팀빌딩데이 킥오프 회의
- 2023.08.07 3차 스프린트 중간회고