본문 바로가기
공부 일지/개인 공부 기록용

프로젝트 역이요 - 리팩토링 3일차

by Joshbla 2023. 5. 15.

주변 정보 추천 기능 수정 1

마지막으로 현재 게시글의 주변에 있는 볼거리를 추천해주는 기능을 수정해줄 차례이다.

이전에 작성했던 방법은 완전 무식하게 모든 게시글을 불러와서 거리를 각각 비교해 준 후 일정 거리 안에 있는 게시글을 모아서 응답해주는 방법을 사용했다.

이것을 mysql의 point 자료형을 이용하는 방식으로 수정해보자.

 

mysql에서 지원하는 ST_distance_sphere 함수를 이용하면 두 좌표간의 거리를 구할 수 있다.

ST_distance_sphere (좌표1, 좌표2);  => 두 좌표간의 거리가 m단위로 주어진다.

 

따라서 특정 위치에서 일정 거리내에 있는 테이블을 모두 조회하려면

// point 는 기준 위치정보 
// board는 게시글 테이블 명 , geography는 위치정보 컬럼명

SET @point = POINT(128.59072079647405, 35.86729311520323);
select * from board b where ST_Distance_Sphere(geography, @point) <= 500;

이와 같이 쿼리를 구성하면 될 것이라고 생각했다.

 

역이요에서는 querydsl을 사용하지 않고 nativequery를 사용했었으므로 직접 작성을 했다.

    @Query(value = "select * from board b where ST_Distance_Sphere(b.geography, :point) <= 500", nativeQuery = true)
    List<Board> findAround(@Param("point")Point point);

 

mysql에서 작성했던 쿼리가 spring에선 동작하지 않았다 에러로그는 다음과 같다.

o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 3037, SQLState: 22001
o.h.engine.jdbc.spi.SqlExceptionHelper   : Data truncation: Invalid GIS data provided to function st_distance_sphere.

잘못된 형식의 데이터가 함수에 사용됐다는 것 같다.

 

챗GPT에 물어봤더니 String 형식을 파라미터로 넣는 것 같다.

@Query(value = "select * from board b where ST_Distance_Sphere(b.geography, :point) <= 500", nativeQuery = true)
    List<Board> findAround(@Param("point")String point);

그랬더니 이번엔 다음과 같은 에러가 발생했다.

o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 3548, SQLState: SR001
o.h.engine.jdbc.spi.SqlExceptionHelper   : There's no spatial reference system with SRID 1313427280.

다시 챗 GPT에게 물어보니

.....

어느장단에 맞추라는 거지

...

 

결국 repository에서는 그대로 Point자료형을 입력하고

@Query(value = "SELECT * from board where ST_Distance_Sphere(geography, :point) <= 500", nativeQuery = true)
List<Board> findAround(@Param("point")Point point);

service단에서 point를 db에서 가져온 그대로 사용한것이 아닌 2차가공을 해주니 성공하였다.

// 기존 방법
List<Board> around = boardRepository.findAround(board.getGeography());// 근처 보드 정보

// 수정 방법
Point point = new GeometryFactory().createPoint(new Coordinate(board.getGeography().getX(), board.getGeography().getY()));
List<Board> around = boardRepository.findAround(point);// 근처 보드 정보

 

도저히 차이점이 뭔지 모르겠어서

다시 원래대로 getGeography()를 통해 얻은 point를 그대로 넣었더니 

이번엔 또 정상적으로 동작한다...

 

그렇다면 결론은 처음에 nativequery를 잘못 작성했던 것 같다.

가까운 길을 멀리 돌아왔다...

 


주변 정보 추천 기능 수정 2

주변 정보추천 기능에서 현재 작성된 방식은

mysql에서 모든 게시글을 가져와서 기준 좌표에서 500m이내에 있는 게시글을 조회한다.

 

이를 좀 더 효율적으로 바꾸기위해 방법을 찾아봤다.

공간 인덱스(Spatial index)를 사용하면 성능을 향상시킬 수 있었다.

 

방식은 처음에 게시글을 모든 게시글을 가져오는 것이 아닌 

현재 좌표 중심으로 원을그려 해당 범위내에 있는 게시글만 조회하는 것이다.

    @Query(value = "SELECT * from board where ST_Contains(ST_Buffer(:point, 0.005),geography)", nativeQuery = true)
    List<Board> findAround(@Param("point")Point point);

ST_Buffer(point, 0.01) 메서드를 사용하면 point를 기준으로 반경 1키로미터 만큼의 원을 그린다.

그리고 ST_Contains() 메서드를 사용하여 해당 범위 내에 좌표가 있는 게시글을 찾는다.

 

모든 게시글을 조회하는 것에서 범위 내의 게시글을 조회하는 방식으로 바꾸는 것이기에

유의미한 성능 변화가 있는 것 같다.

 

프로젝트를 마무리한지 4달정도 지나고 리팩토링을 한 것인데 새로 공부하고 알게된 내용이 있어서 수정할 부분이 꽤 있었다. 리팩토링을 하면서 mysql의 Point자료형에 대해서 많이 공부해볼 수 있었고 nativequery 사용법도 복습해보며 좋은 공부가 됐다. 

'공부 일지 > 개인 공부 기록용' 카테고리의 다른 글

[JPA] N+1 문제  (0) 2023.05.22
에러로그 (mysqladmin flush-hosts)  (0) 2023.05.19
프로젝트 역이요 - 리팩토링 2일차  (0) 2023.05.13
프로젝트 역이요 - 리팩토링 1일차  (0) 2023.05.11
23/05/08  (0) 2023.05.09