지도이야기 | Geo 함수 - 거리구하기

보람·2022년 3월 19일
1
post-thumbnail

point, linestring, polygon, geometry 등 디비로 표현할 수 있는 지도 데이터는 다양합니다.
다양한 타입에 데이터를 조금 더 유용하게 사용할 수 있도록 해준 함수들도 물론 존재했습니다.

그중에서 이번글에서는 두 위치 사이의 거리를 구하는 함수에 대해 설명하고자 합니다.

구글맵에서 손이 가는대로 아무곳이나 A, B 두곳을 찍어서 거리를 구해봤습니다.
위와 같은 A, B 위치가 있고 두 위치 사이의 거리가 76.04m라는 값이 화면상에 표시됩니다.

구글맵에서 두 위치 사이의 거리를 알려주는 것처럼 같은 기능을 sql을 통해서 얻어내고자 합니다.

A와 B 사이의 거리를 구하고자 할때 수학시간에 배웠던 거리 구하는 공식대로 각각의 경도, 위도를 그 식에 대입해서 구하는 방법대로 거리를 구한다고 하면 구하고자 하는 그 식이 엄청 길어질 것입니다. 이런 경우에 아래와 같은 함수를 사용할 수 있습니다.

ST_Distance(p1, p2) : 평면에서 두 점들 사이의 거리 구하기

select st_distance(POINT(128.89545004049526, 37.718265020117755), 
                   POINT(128.89472519954293, 37.71788979005703)); 


잉! 그런데 결과값이 예상했던 값이 나오지 않습니다.
76m라는 값이 나와야 하는데 1 이하의 소수점이 떨어집니다.

우리가 살고 있는 지구는 평면이 아니라 둥글기 때문에 평면위에 두점 사이의 거리를 구하는 해당 함수로는 지구상의 거리를 알 수 없습니다.

SRID-0, SRID-4326

  • SRID-0 : 단순 직교 좌표계 의미
  • SRID-4326 : GPS의 기준이 되는 좌표계 의미

바로 st_distance()는 srid-0을 기준으로 즉, 단순 직교 좌표로 계산을 하기 때문입니다.

해당 함수는 MySQL 버전에 따라서 다르게 반응합니다.

MySQL 8.0

MySQL 8.0 부터는 아래와 같이 사용한다면 76m라는 값을 st_distance()를 이용해서 구할 수 있습니다. srid-4326으로 변환한다면 인식을 할 수 있도록 돼있습니다.

set @loc = ST_SRID(Point(128.89472, 37.71788), 4326);
set @loc2 = ST_SRID(Point(128.89545, 37.71826), 4326);

select ST_Distance(@loc, @loc2)                       as distance,
       ST_Distance_Sphere(Point(128.89472, 37.71788),
                          Point(128.89545, 37.71826)) as distance_sphere;

sql이 조금 더 길어졌지만 원하고자 하는 값을 구하긴 했습니다.

MySQL 5.X

하지만 8.0버전이 아닌 MySql 5.X을 사용한다면 srid-4326을 인식하지 못하기 때문에 원하는 값이 나오지 않습니다. 아래 이미지는 5.X버전으로 select해본 결과입니다.

때문에 MySQL 버전에 대한 고민 없이 평면이 아닌 지구상의 위치 사이의 거리를 구하고자 할 때 우리는 아래 함수를 사용할 수 있습니다.

ST_Distance_Sphere(p1, p2) : 구 안에서 두 좌표 사이의 거리 → 지구 거리를 구해야 하므로 해당 함수로 거리 조회해야함

우리가 살고있는 지구는 평면이 아니라 둥글기 때문에 srid-4326을 기반으로 계산하는 st_distance_shpere()함수를 사용해야만 원하는 76m라는 값을 구할 수 있습니다.

select st_distance_sphere(POINT(128.89545004049526, 37.718265020117755), 
                          POINT(128.89472519954293, 37.71788979005703));


76m라는 원하는 값을 얻었습니다.

이러한 거리 구하기 함수는 아래와 같은 경우에 사용할 수 있을 것 같습니다.

거리위에 한 사람이 있고 특정 건물들이 존재할 때 우리는 위 함수를 사용하여서 어떤 건물이나 기기들이 더 가까운 곳에 존재하느냐? 에 대한 결과를 얻을 수 있습니다.
쿼리는 아래와 같은 형태입니다.

SELECT id,
       point_info,
       st_distance_sphere(point_col, POINT(126.97725, 37.570892)) as distance
FROM test_point 
ORDER BY distance
limit 1

내 주변 상점 구하기 같은 기능도 limit N(특정수치) 만 지정한다면 위같은 sql로 구할 수 있을 것 같습니다.

물론 geo 타입 컬럼에 spatial index 까지 걸어야만 조금 더 빠르게 원하는 결과를 얻을 수 있습니다.

한가지 아쉬운 점이 있다면 st_distance_sphere() 함수는 점과 점 사이의 거리만을 측정한다는 것입니다.

만일 geometry 타입과 한 점 사이의 거리가 Nm가 걸리는지에 대해 구하고자 할때는 MySQL 8.0 버전을 사용한다면 아래와 같은 형식으로 구할 수 있습니다.

SELECT id,
       st_distance(st_srid(geometry_col, 4326), ST_SRID(Point(128.89472, 37.71788), 4326) ) as distance
FROM test_location
ORDER BY distance
limit 10

geometry_col 은 geo 타입의 point, polygon, geometry 타입의 컬럼 모두 들어갈 수 있습니다.

DB를 이용해서 두 위치 사이에 거리를 구하는 함수에 대해서 작성해봤습니다.

간단해보이는 함수지만 이러한 함수가 있는 것을 알았기에 조금 더 간편하게 거리를 구할 수 있으리라 생각합니다!
해당 함수는 위치 기반 타입에 대해 조사하던 중에 찾았던 함수인데 아쉽게도 아직 몇몇 이유로 회사 프로젝트에서 사용하진 못했습니다. 하지만 이렇게 조사하고 정리하면 언젠가 사용할 날이 왔을때 바로 꺼내서 쓸 수 있을것이라 믿습니다.🌝

해당 글에 작성된 sql은 MySQL을 기반으로 작성했지만 geo-타입을 제공하는 다른 DB에서도 사용할 수 있을 것이고 이후에도 위치 관련된 업무를 할때 많은 도움이 될 것이라고 저는 생각했습니다!

다음에는 위치의 교차 여부에 대해 구할 수 있는 함수에 대해 작성해보려 합니다.

profile
백엔드 개발자

0개의 댓글