enginner_s2eojeong
JPA에서 Index 설정하는 방법 (feat. 쿼리 속도 향상 시키기) - 2편 본문
2025.02.13 - [Backend/Database] - JPA에서 Index 설정하는 방법 (feat. 쿼리 속도 향상 시키기) - 1편
JPA에서 Index 설정하는 방법 (feat. 쿼리 속도 향상 시키기) - 1편
ReciGuard 프로젝트 회고ReciGuard는 알레르기를 가진 사용자에게 안전한 레시피를 추천하는 서비스다. 때문에 사용자별 알레르기 정보를 반영하기 위해 정규화된 데이터베이스 구조를 설계하였
s2eojeong.tistory.com
지난 시간에는 JPA로 Index를 설정하는 방법을 배웠다.
이제 Index를 활용해서 기존 JPQL 쿼리를 리팩토링 해보자 !
RecipeRepository에는 DB에서 특정 레시피를 조회하는 함수들이 존재하는데,
1. 모든 레시피 조회, 2. cuisine별로 레시피 조회, 3. 검색어로 레시피 조회
이렇게 총 3가지의 레시피 조회가 있다.
여기에서 또, 사용자에게 알레르기를 유발할 수 있는 재료의 재료명과 정확히 '일치'하거나 '포함'하는 레시피를 필터링하는 기능들이 각각 필요하다.
가정) 현재 로그인 한 사용자
"계란", "참깨" 알레르기가 있는 사용자를 가정하였다.
이제부터 각각의 3개의 쿼리에 대해 Index 생성 전, 후로 나누어 실행 시간 차이를 알아보자.
1. findAllFilteredRecipes
@Query("""
SELECT DISTINCT r
FROM Recipe r
WHERE NOT EXISTS (
SELECT 1
FROM RecipeIngredient ri
JOIN Ingredient i ON ri.ingredient.id = i.id
WHERE ri.recipe.id = r.id
AND EXISTS (
SELECT 1
FROM UserIngredient ui
JOIN Ingredient ing ON ui.ingredient.id = ing.id
WHERE ui.user.id = :userId
AND (i.id = ing.id
OR i.ingredient LIKE CONCAT('%', ing.ingredient, '%'))
)
)
""")
List<Recipe> findAllFilteredRecipes(@Param("userId") Long userId);
약 20% 정도의 성능 향상
2. findCusineFilteredRecipes
@Query("""
SELECT DISTINCT r
FROM Recipe r
WHERE r.cuisine = :cuisine
AND NOT EXISTS (
SELECT 1
FROM RecipeIngredient ri
JOIN Ingredient i ON ri.ingredient.id = i.id
WHERE ri.recipe.id = r.id
AND EXISTS (
SELECT 1
FROM UserIngredient ui
JOIN Ingredient i2 ON ui.ingredient.id = i2.id
WHERE ui.user.id = :userId
AND (
i2.ingredient = i.ingredient
OR i.ingredient LIKE CONCAT('%', i2.ingredient, '%')
)
)
)
""")
List<Recipe> findCuisineFilteredRecipes(@Param("userId") Long userId, @Param("cuisine") String cuisine);
약 6.8% 정도의 성능 향상
3. findQueryFilteredRecipes
@Query("""
SELECT DISTINCT r
FROM Recipe r
WHERE (r.recipeName LIKE CONCAT('%', :query, '%'))
AND NOT EXISTS (
SELECT 1
FROM RecipeIngredient ri
JOIN Ingredient i ON ri.ingredient.id = i.id
WHERE ri.recipe.id = r.id
AND EXISTS (
SELECT 1
FROM UserIngredient ui
JOIN Ingredient i2 ON ui.ingredient.id = i2.id
WHERE ui.user.id = :userId
AND (
i2.ingredient = i.ingredient
OR i.ingredient LIKE CONCAT('%', i2.ingredient, '%')
)
)
)
""")
List<Recipe> findQueryFilteredRecipes(@Param("userId") Long userId, @Param("query") String query);
약 36.6%정도의 성능 향상
다만 기존에 설정된 사용자 알레르기 정보에 따라 쿼리 성능 향상에 편차가 약간씩 생긴 것 같다.
그래도 1,3번에 대해서는 각각 20%, 36% 정도의 성능 향상을 가시적으로 확인할 수 있어서 성공적인 실습이었던 것 같다.
지금은 학부생 수준에서 진행한 프로젝트라 데이터라 한 테이블에 대략 1200개 정도로 적은 양이지만 나중에 대량의 데이터를 다루게 된다면 인덱스를 활용한 성능 향상은 필수적일 것으로 생각한다.
'Backend > Database' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 03.영속성 관리 (1) | 2025.03.19 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 02.JPA 시작 (1) | 2025.03.16 |
[자바 ORM 표준 JPA 프로그래밍] 01.JPA 소개 (2) | 2025.03.14 |
Full Text Search를 이용한 DB Optimization (0) | 2025.02.14 |
JPA에서 Index 설정하는 방법 (feat. 쿼리 속도 향상 시키기) - 1편 (0) | 2025.02.13 |