본문으로 건너뛰기
6.3 GiST와 SP-GiST 인덱스

6.3 GiST와 SP-GiST 인덱스

GiST(Generalized Search Tree)와 SP-GiST(Space-Partitioned GiST)는 B-tree로는 다루기 어려운 데이터 타입 — 공간 좌표·범위 타입·IP 네트워크·기하 도형·full-text vector 등 — 을 인덱싱하는 일반화된 트리 인덱스입니다. 운영자는 PostGIS·범위 쿼리 작업에서 가장 자주 마주칩니다.

GiST 개요

GiST는 balanced search tree의 framework다. 새 데이터 타입의 비교·containment 연산을 정의하면 해당 타입을 인덱싱할 수 있게 해 주는 일반 구조 — “확장 가능한 B-tree"라고 보면 됩니다.

잘 처리하는 쿼리예시
공간 containmentWHERE geom && ST_MakeEnvelope(...) (PostGIS)
범위 타입 overlapWHERE tsrange && '[2026-01-01, 2026-02-01)'::tsrange
nearest neighborORDER BY point <-> POINT '(1,2)' LIMIT 10 (KNN)
IP/network 포함WHERE inet_col >> '10.0.0.0/8'
full-text similaritytrigram WHERE col % 'query' (pg_trgm)
도형 교차WHERE box1 && box2

GiST 인덱스 만들기

-- 범위 타입 — 회의실 예약 충돌
CREATE INDEX idx_meetings_when ON meetings USING gist (when_range);

-- 충돌 쿼리
SELECT * FROM meetings
 WHERE when_range && '[2026-05-23 10:00, 2026-05-23 11:00)'::tsrange;
-- PostGIS geometry
CREATE INDEX idx_parcels_geom ON parcels USING gist (geom);
-- KNN search (가장 가까운 N개)
CREATE INDEX idx_points ON places USING gist (location);
SELECT name FROM places ORDER BY location <-> POINT '(127.0, 37.5)' LIMIT 5;

EXCLUSION CONSTRAINT

같은 시간대 충돌을 DB 수준에서 막는 강력한 패턴:

CREATE TABLE meetings (
  id serial PRIMARY KEY,
  room_id int,
  when_range tsrange,
  EXCLUDE USING gist (
    room_id WITH =,
    when_range WITH &&
  )
);

같은 room_id + 시간 범위가 겹치는 row 두 개가 동시에 존재할 수 없도록 보장. INSERT가 충돌하면 PostgreSQL이 자동 거부합니다. row-level 락 없이 일관성 유지합니다.

buffering / fillfactor

큰 데이터로 GiST를 처음 만들 때 buffering = on 옵션을 쓰면 빌드가 빨라진다:

CREATE INDEX idx_big_geom ON big_table USING gist (geom)
  WITH (buffering = on, fillfactor = 90);

fillfactor는 B-tree와 비슷 — 페이지 분할 빈도와 BLOAT 트레이드오프.

SP-GiST 개요

SP-GiST는 공간 분할 트리(quad-tree, k-d tree, radix tree, suffix tree 등)를 일반화한 인덱스. GiST와 비슷한 데이터 타입을 다루지만 부모-자식이 겹치지 않는 분할이 핵심이라 일부 쿼리에서 더 빠릅니다.

잘 처리하는 쿼리예시
Point in boxWHERE point <@ box
IP 라우팅 트리WHERE inet_col <<= '10.0.0.0/8'
text prefix(트리/radix)WHERE textcol LIKE 'foo%' (text_ops opclass)
CREATE INDEX idx_ips_spgist ON connections USING spgist (src_ip);

GiST vs SP-GiST 선택

측면GiSTSP-GiST
트리 구조balanced, 자식 영역 겹침 가능unbalanced, 자식 영역 겹침 없음
강한 분야overlap·containment·KNNpoint lookup, prefix·radix
BLOAT 회복REINDEXREINDEX
Index-only scan일부 가능일부 가능
WAL 지원있음있음 (PG 11+)
운영 도구 지원더 많음적음

의사 결정 순서:

  1. 공간·범위·KNN — GiST부터
  2. 정확 point lookup 또는 명확한 비겹침 분할 가능 — SP-GiST가 더 빠를 수 있음
  3. 둘 다 후보면 GiST를 기본, 성능 측정 후 SP-GiST 검토

보조 확장과 짝

확장GiST/SP-GiST 활용
PostGISgeometry, geography, raster 모두 GiST
btree_gistint·timestamp 등 B-tree 타입을 GiST에 끼워 넣어 exclusion constraint 조합 가능
pg_trgm텍스트 trigram — LIKE '%foo%'·유사도 검색 (GIN도 가능)
cube다차원 공간 (KNN)

btree_gist 예시 — room_id(int)와 when_range를 한 EXCLUSION에 같이:

CREATE EXTENSION btree_gist;
CREATE TABLE meetings (
  ...,
  EXCLUDE USING gist (room_id WITH =, when_range WITH &&)
);

btree_gist 없으면 room_id(int)에 = 연산자를 GiST가 못 다룹니다.

운영 시 주의

주의메모
GiST 빌드는 B-tree보다 느림큰 테이블은 CONCURRENTLY + buffering = on 권장
인덱스 크기가 큼leaf entry에 키 외에 페이지 boundary 정보도 포함
VACUUM이 dead entry 정리 — BLOAT 대응REINDEX CONCURRENTLY 필요
KNN(ORDER BY x <-> y)는 GiST만 가능SP-GiST는 KNN 미지원 (PG 18 기준)
PostGIS 운영자라면 GiST는 기본 도구. CREATE EXTENSION postgis; 후 모든 geometry/geography 컬럼에는 거의 자동으로 GiST를 만들게 됩니다. PostGIS는 별도 책 한 권 분량이 필요해 본 문서는 PG 코어 인덱스에 집중.

정리

  • GiST = 공간·범위·KNN·overlap·containment에 강한 일반화 트리
  • SP-GiST = 비겹침 분할 트리. point lookup·radix·prefix에서 GiST보다 빠를 수 있음
  • EXCLUSION CONSTRAINT는 GiST의 강력한 사용 사례 — 동시에 겹치는 row를 DB에서 막음
  • btree_gist 확장으로 평범한 타입을 GiST에 끼워 multi-key constraint 가능
  • 큰 테이블 인덱스 빌드는 CONCURRENTLY + buffering 권장
  • KNN은 GiST 전용

다음 절(6.4)에서는 JSONB·full-text search·배열에 표준인 GIN 인덱스를 봅니다.