Java & Spring/고도화

MySQL 공간 인덱스(Spatial Index) 적용 - 체육관 검색

DJ.Kang 2024. 11. 14. 16:38

 MySQL 공간 함수 공식 문서

□ 전체 QueryDsl 코드

- MySQL의 공간인덱스를 사용하기 위해 Point타입을 사용

 @Override
    public Page<GymSimpleResponse> search(String name, String address, GymType gymType,
                              Point userLocation, Double requestDistance, Pageable pageable) {

        BooleanExpression condition = buildSearchCondition(
                name, address, gymType, userLocation, requestDistance);

        NumberTemplate<Double> distanceTemplate = Expressions.numberTemplate(
                Double.class,
                "ST_Distance_Sphere({0}, {1})", gym.location, userLocation
        );

        JPAQuery<Tuple> query = jpaQueryFactory
                .select(gym, distanceTemplate)
                .from(gym)
                .where(condition)
                .orderBy(distanceTemplate.asc());

        // 페이지로 변환
        List<GymSimpleResponse> gymResponses = query
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch()
                .stream()
                .map(tuple -> new GymSimpleResponse(
                        tuple.get(gym).getName(),
                        tuple.get(gym).getRegionAddress(),
                        Double.valueOf(String.format("%.1f", tuple.get(distanceTemplate) / 1000))
                ))
                .filter(gymSimpleResponse -> gymSimpleResponse.getDistance() <= requestDistance)
                .collect(Collectors.toList());

        long total = query.fetchCount();

        return new PageImpl<>(gymResponses, pageable, total);
    }

□ 개선 전

- ST_Distance_Sphere() : 두 좌표 사이 구형 거리를 구하는 함수

    NumberTemplate<Double> distanceTemplate = Expressions.numberTemplate(
                Double.class,
                "ST_Distance_Sphere({0}, {1})", gym.location, userLocation
        );
  • NumberTemplate<T> : QueryDSL의 숫자 표현 클래스, Double을 타입으로 지정하여 표현식의 결과가 Double 타입임을 나타냄
  • Expressions.numberTemplate(Class, Template) : 표현식을 생성하는 정적 메서드, NumberTemplate을 생성하며, SQL 함수나 특정 데이터베이스 함수와 같은 맞춤형 표현식을 만들 수 있다.

- 성능

테스트환경
응답속도
최초 증가 최종
시간
v3
1 0 1
30s
576.94
10 0 10 1465.33
10 10 100 10953.74

- 쿼리 실행계획

 

□ 개선 후

- ST_Contains(ST_Buffer(), Point) : 하나의 공간 객체 다른 공간객체에 포함되는지 확인하는 함수

Expressions.booleanTemplate("ST_CONTAINS(ST_Buffer({0}, {1}), {2})",
                            userLocation, requestDistance, gym.location
                            )
  • Boolean을 통해 범위 내 포함되는지 확인
  • ST_Contains() : 하나의 공간객체가 다른 공간객체를 포함하는지 확인
  • ST_Buffer() : 지정한 지점에 일정한 반경의 버퍼를 생성
  • userLocation기준 requestDistaqnce크기의 Buffer를 생성 후 gym.location이 포함되는지를 확인

※ ST_Contains는 공간 인덱스(Spatial Index)를 활용할 수 있으므로 성능 향상 기대

 

- 성능

테스트 환경 응답속도
최초 증가 최종 시간 v4
1 0 1
30s
157.1
10 0 10 125.88
10 10 100 165.58

- 쿼리 실행계획

 

□ 성능비교

최소 3.6배, 부하에 따라 더욱 향상된 성능을 보여준다

테스트환경 응답속도(ms)
성능차이
최초 증가 최종 시간 v3 v4
1 0 1
30s
576.94 157.1 367.24%
10 0 10 1465.33 125.88 1164.07%
10 10 100 10953.74 165.58 6615.38%