참고 : 공간 데이터 개념부터 적용까지
MySQL에는 7개의 공간 데이터가 있다.
단일타입은 Point, LineString, Polygon 세 가지가 있다.
나머지는 이것들을 활용하는 것이다.
이 데이터 타입을 쓰면 공간함수를 쓸 수 있게 된다.
SRID(Spatial Reference Identifier)는 데이터 좌표계를 구분할 수 있는 식별 코드다.
가장 흔하게 사용되는 값은 4326으로 위도(Latitude)와 경도(Longitude)를 사용하여 위치를 표현하는 WGS84 좌표계를 의미한다. 이는 GPS 및 다양한 GIS 솔루션에서 널리 사용된다고 한다. 카카오맵 같은 경우도 이 좌표계를 사용한다.
MySQL에 입력되는 데이터에도 이 SRID 값을 지정해 줄 수가 있다.
CREATE TABLE sridTest2 (
id bigint auto_increment primary key,
point point SRID 4326
);
공간 데이터도 조회 성능 향상을 위해 인덱스를 사용할 수 있다.
CREATE SPATIAL INDEX idx_point ON sridTest2(point);
CREATE SPATIAL INDEX [인덱스 명] ON [테이블 명](컬럼 명);
MySQL의 공간 인덱스는 MBR의 포함관계를 바탕으로 트리 구조를 생성하여 이용한다. MBR(Minimum Bounding Rectangle)의 약어로 최소 경계 사각형을 의미한다.
각각의 물체들을 최소 경계 사각형으로 감싸면, 이게 MBR이 된다.
인덱스가 B-Tree를 쓰는 것처럼, 공간 인덱스는 R-Tree라는 트리 형태의 자료구조를 이용한다.
MBR 포함 관계를 트리로 표현한 것이다.
삽입 및 삭제 과정에서도 B-Tree와 마찬가지로 동적으로 재구성되어
leaf node들의 균형을 유지한다.
탐색 속도를 향상하기 위해 자식 노드들의 적정 개수를 유지하며, 삽입 과정에서 MBR의 크기가 작게 확장되는 분기를 선택한다.
균형유지
root node부터 모든 leaf node까지의 거리가 동일하게 유지된다.
실제 지리도 이런 식으로 MBR를 설정할 수 있다.
테코블 글을 보면, 이런 식으로 MBR들이 좀더 상위의 MBR에 포함되는 형식인 거 같다.
새로운 데이터 추가
X데이터가 추가되면
이를 포함하는 가장 작은 MBR에 포함된다.
경계에 포함되지 않는 데이터 추가
이렇게 경계에 포함되지 않는 데이터가 있다면?
MBR이 가장 적게 확장되는 E로 들어가게된다
(크기를 가장 조금만 키워도 저걸 포함시킬 수 있는 MBR로)
검색할 때 이 MBR이 활용된다.
그림에서 분홍색 원안에 포함되어있는 모든 데이터를 반환하는 경우를 가정해보자.
분홍색 원에 A MBR 과 B MBR이 모두 걸쳐 있기 때문에, A 와 B 모두 확인을 해본다.
A 의 자식 노드들 중에는 분홍색 원의 범위에 포함되는 MBR이 없으므로 A 브랜치의 검색은 종료된다.
반면, B 의 자식 노드들 중에는 D 가 범위에 포함되어 있다.
그리고 D의 자식 노드 중 M이 범위에 포함되기에 M의 데이터를 반환한다.
이렇게 해도 인덱스가 적용되지 않는 경우가 있다
SELECT * FROM example WHERE ST_DISTANCE(point, ST_GeomFromText('POINT(10 20)', 4326)) <= 5000
ST_DISTANCE 함수를 활용해서 point 와 기준점(10, 20)의 거리가 5KM 이하인 모든 데이터를 가져오는 쿼리다.
R-Tree는 MBR들의 포함관계를 이용하여 만들어진 트리라고 했다.
하지만 위의 ST_DISTANCE를 사용한 쿼리는 포함관계를 확인하는 것이 아니다.
모든 데이터와 기준점과의 거리를 계산하여 반환하는 쿼리이다.
이러한 케이스는 ST_DISTANCE 대신 ST_CONTAINS와 ST_BUFFER를 활용하면 해결할 수 있다.
SELECT * FROM example WHERE ST_CONTAINS(ST_BUFFER(ST_GeomFromText('POINT(10 20)', 4326), 5000), point);
ST_BUFFER 는 첫 번째 인자를 중심점으로 반지름이 두 번째 인자인 원을 그리는 함수다.
ST_CONTAINS 는 첫 번째 인자가 두 번째 인자를 포함하는지 여부를 확인하는 함수이다.
즉, 위의 쿼리는 POINT(10 20)을 중심으로 반경 5KM 내에 있는 데이터를 조회하는 쿼리이다.
수정한 쿼리는 공간 데이터 간의 포함관계를 이용하므로, 인덱스가 잘 적용되는 것을 확인할 수 있다.
두번째 사례는 SRID 미 적용인 경우다.
세 군데에 적용한 SRID 값이 모두 일치해야 인덱스가 정상적으로 동작한다.
SELECT * FROM example WHERE ST_CONTAINS(ST_BUFFER(ST_GeomFromText('POINT(10 20)'), 5000), point);
위에서 사용한 쿼리를 예로 들어보자면, ST_GeomFromText 함수에 두 번째 인자로 SRID 값이 빠져있다. 이런 경우에는 SRID값이 default인 0으로 지정되는데, 이때 point 데이터의 SRID값이 0이 아니라면 인덱스는 적용되지 않는다.
포함관계를 이용한 검색의 경우에는 SRID 값이 일치해야 인덱스가 적용된다.