위치 기반 서비스를 설계하거나, 위치 정보 기반의 데이터 마트를 만들다 보면 자연스럽게 마주치는 개념이 있다. 바로 "공간 인덱스(Spatial Index)"이다. 처음에는 생소하지만, GPS 좌표, 지점 정보, 영역(예: 행정구역, 반경 등)을 다루는 시스템에서 이 인덱스는 성능과 정확도의 핵심이다. 이번 글에서는 공간 인덱스의 대표 주자인 R-Tree에 대해 살펴봤다.

 

특히 왜 기존의 인덱스(B-Tree)만으로는 부족한지, 그리고 R-Tree가 어떻게 공간 데이터를 효율적으로 처리하는지 실전적인 관점에서 접근해본다.


왜 공간 인덱스가 필요한가?

일반적으로 RDB에서는 데이터를 효율적으로 검색하기 위해 B-Tree 기반의 인덱스를 사용한다. 하지만 위치 정보는 단순 정렬이 아닌 2차원 좌표계에서의 포함, 거리, 교차 등의 연산이 필요하다. 예를 들어:

  • 반경 5km 내의 점 찾기
  • 특정 영역(행정구역, 사각형, 원형 등)에 포함되는 지점 찾기
  • 위치 간의 거리 계산

이런 연산을 B-Tree로 처리하려면 매우 복잡해지고, 성능도 현저히 떨어진다. 이럴 때 필요한 것이 공간 인덱스이며, 그중 대표적인 구조가 R-Tree이다.


R-Tree란 무엇인가?

R-Tree는 1984년 Antonin Guttman이 제안한 구조로, 사각형의 사각형으로 구성된 트리이다. 정확히는 각 노드가 **MBR(Minimum Bounding Rectangle, 최소 경계 사각형)**을 갖고 있고, 이 사각형들이 트리처럼 계층적으로 구성된다.

구조 예시 (텍스트 기반)

        [전체 지도 MBR]
            /       \
       [서울]     [부산]
       /     \\       \
   [점1]   [점2]   [점3]
  • 루트 노드: 전체 범위를 포함
  • 내부 노드: 특정 지역의 MBR (예: 서울)
  • 리프 노드: 실제 좌표 데이터 (POINT)

쿼리를 할 때는, 조건과 겹치는 MBR만 탐색하면 되므로 효율적이다.


공간 데이터의 표현: POINT, POLYGON, SRID

공간 인덱스를 쓰기 위해서는 공간 데이터를 명확하게 표현할 수 있어야 한다. MySQL이나 PostGIS 등에서 제공하는 공간 타입은 다음과 같다:

타입 설명
POINT 위경도 좌표 한 점 (예: 지점 위치)
POLYGON 닫힌 다각형 영역 (예: 행정구역, 구역 경계)
LINESTRING 선 (예: 경로, 도로)
GEOMETRY 위 모든 타입을 포함하는 상위 타입

또한 좌표에는 반드시 어떤 좌표계를 기준으로 했는지 정의해야 하는데, 이를 "SRID (Spatial Reference System Identifier)"라고 한다.

  • 예: SRID 4326 = WGS 84 좌표계 (GPS에서 사용하는 위경도)

SRID가 제대로 적용되었는지 확인하는 방법

테이블 생성 시 POINT SRID 4326처럼 명시했더라도, 실제로 적용되었는지 헷갈릴 수 있다. 이를 확인하는 방법은 다음과 같다:

1. information_schema.ST_GEOMETRY_COLUMNS 조회

SELECT *
FROM information_schema.ST_GEOMETRY_COLUMNS
WHERE table_schema = 'your_schema'
  AND table_name = 'your_table';

여기서 srs_id가 4326이면 SRID가 적용된 것이다.

2. SHOW CREATE TABLE로 SRID 확인

SHOW CREATE TABLE your_table;

정상 적용 시 POINT /*!80003 SRID 4326 */ 형식으로 출력된다. (MySQL 8.0 이상)

3. ST_SRID() 함수로 확인

SELECT ST_SRID(location) FROM your_table LIMIT 1;

값이 4326이면 SRID가 적용된 것이다. 0이면 적용되지 않은 것이다.

SRID가 설정되지 않은 상태에서는 거리 계산, 포함 연산 등이 예상대로 작동하지 않을 수 있으므로 반드시 확인이 필요하다.


MySQL에서 공간 인덱스 사용 예시

MySQL 8.0 이상에서는 공간 데이터 타입과 R-Tree 기반 공간 인덱스를 사용할 수 있다.

CREATE TABLE geo_locations (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(100),
  location POINT SRID 4326,
  SPATIAL INDEX(location)
);

INSERT INTO geo_locations (name, location)
VALUES ('Sample Place', ST_GeomFromText('POINT(127.0 37.5)', 4326));

SELECT name FROM geo_locations
WHERE ST_Distance_Sphere(location, ST_GeomFromText('POINT(127.0 37.6)', 4326)) < 1000;

이 쿼리는 기준 위치(127.0, 37.6)에서 반경 1km 이내에 있는 지점을 검색한다.

📌 참고: ST_Distance_Sphere는 구면 좌표계 기준으로 거리 계산 (미터 단위)

주요 공간 함수 요약

함수 설명
ST_Distance() 평면 거리 계산 (SRID 0 기반)
ST_Distance_Sphere() 구면 거리 계산 (SRID 4326 기반)
ST_Within(a, b) a가 b 안에 있는지 여부
ST_Contains(a, b) b가 a 안에 포함되는지 여부
ST_Intersects(a, b) 두 객체가 교차하는지 여부
ST_Buffer(geom, dist) 주어진 거리만큼 영역 생성 (예: 반경 검색용)

이러한 공간 함수는 공간 인덱스와 함께 사용될 때 특히 강력하며, 수많은 위치 기반 서비스에서 핵심 역할을 한다.

 

공간 인덱스 없이 공간 함수를 사용할 경우의 한계

공간 함수는 공간 인덱스 없이도 작동한다. 예를 들어 ST_Distance_Sphere()ST_Within() 등의 함수는 실행 자체는 가능하다. 하지만 공간 인덱스가 없다면:

  • 전체 테이블을 풀스캔하게 된다.
  • 결과적으로 성능 저하가 크고, 특히 데이터 양이 많을수록 쿼리 속도가 급격히 느려진다.
  • 인덱스가 없는 상태에서 공간 함수는 단순 계산을 반복하는 수준에 그쳐, 공간 연산의 이점을 살리지 못한다.

즉, 공간 인덱스는 공간 함수의 정확도보다는 성능 최적화에 핵심 역할을 하며, 대규모 위치 기반 데이터 처리에서 필수적이다.


마치며

공간 인덱스는 단순한 기술이 아닌, 위치 기반 데이터를 정밀하고 빠르게 다루기 위한 핵심 도구이다. B-Tree로는 부족한 공간 연산을 R-Tree는 자연스럽게 처리할 수 있고, MySQL/PostGIS 같은 DB에서 이를 적극 활용할 수 있다. 위치 기반 데이터 마트를 설계하거나, 반경 검색/영역 포함 판단이 중요한 프로젝트에서 공간 인덱스를 고려하는거도 좋은 경험이 될 것으로 보인다.

+ Recent posts