TECH 으로 돌아가기
TECH HACKER NEWS 오늘 8분 읽기 32 READS

포스트그레스에 붙는 새 전문검색 엔진 'TIN', ctid를 무기로 삼다

포스트그레스에 붙는 새 전문검색 엔진 'TIN', ctid를 무기로 삼다
SOURCE IMAGE · HACKER NEWS

전문검색(full-text search)은 포스트그레스(Postgres) 사용자들이 가장 자주 요구하는 기능 중 하나다. 제품 검색, 문서 검색, 태그 집계처럼 애플리케이션 성격에 따라 요구사항이 제각각이지만, 기존 포스트그레스 생태계에서는 이를 한 번에 만족시키는 인덱스를 찾기 어려웠다. 플래닛스케일(PlanetScale)이 2026년 9월 공개한 TIN은 바로 이 지점을 겨냥한 전문검색 확장 기능이다. 이름은 'Text INdex'의 약자로, 포스트그레스와 네키(Neki) 데이터베이스에서 정식(GA) 버전으로 곧바로 사용할 수 있다.

무엇을 풀려는 문제인가

전문검색은 단순히 단어를 찾는 것으로 끝나지 않는다. 이커머스 플랫폼은 검색어에 포함된 모든 키워드를 담은 상위 10개 상품을 BM25 점수로 정렬해 보여줘야 하고, 법률 디스커버리 플랫폼은 순위와 무관하게 특정 키워드 하나라도 포함한 모든 문서를 반환해야 하며, 사진 태깅 서비스는 특정 태그가 붙은 사진의 정확한 개수를 세야 한다. 즉 교집합(conjunction), 합집합(disjunction), 구문(phrase) 질의와 순위 매기기, 개수 집계가 모두 필요하다.

여기에 더해 실무 환경에서는 조인, 여러 컬럼에 걸친 복잡한 WHERE 절, 지속적인 삽입·수정·삭제, 복제, 백업, 그리고 올바른 트랜잭션 가시성까지 요구된다. 새로 커밋된 행은 즉시 검색 결과에 반영돼야 한다. 개발사는 이미 세 종류 이상의 포스트그레스 전문검색 인덱스가 존재하지만 이 요건을 모두 충족하는 것은 없었고, TIN이 그 공백을 메운다고 주장한다.

벤치마크가 말하는 것

성능 검증을 위해 개발사는 위키피디아 전체, 2.3TB 분량의 레딧 댓글, 797GB 규모의 혼합 코퍼스 등을 시험했고, 기사에 공개한 수치는 스택익스체인지 질의응답 85GB(1억 5천만 문서)를 대상으로 한 결과다. 표준 질의 트레이스가 없어 2~15개 단어 구간을 표본 추출해 교집합·합집합·구문 세 방식으로 해석한 1,719개 합성 질의를 만들었다. 테스트는 AWS i7i.8xlarge 인스턴스 위에서 8 vCPU, 32GB RAM으로 제한한 컨테이너에 포스트그레스 18.6을 올려 진행했다. 인덱스가 버퍼에 다 들어가지 않는 상황을 일부러 만든 것이다.

비교 대상은 TIN v1.0.2, ParadeDB v0.25.2, pg_textsearch v1.4.0, 그리고 포스트그레스 내장 GIN 인덱스였다. 그런데 TIN을 제외하면 모든 벤치마크를 완주한 것은 ParadeDB뿐이었다. GIN은 합집합 검색에서 메모리 부족으로 탈락했고, pg_textsearch는 합집합 질의만 처리할 수 있어 대부분의 시나리오에서 빠졌다. 수치 자체는 상당히 공격적이다. 동시 쓰기가 없는 혼합 질의에서 TIN은 ParadeDB보다 초당 처리량이 25배 높고 p99 지연은 26배 낮았으며, 교집합·구문 질의에서는 GIN 대비 처리량 541배, 지연 1,356배 차이를 기록했다. 초당 1,000건의 UPDATE가 동시에 들어오는 상황에서도 10분간 TIN은 27만여 건의 업데이트를 소화한 반면 pg_textsearch는 735건에 그쳤다.

빠름의 근원, ctid

TIN이 이런 격차를 만들어내는 핵심은 문서 식별자 설계에 있다. 대부분의 전문검색 시스템은 인덱스를 세그먼트로 나누고 각 세그먼트 안에서 문서에 1부터 n까지 순차 번호를 매긴다. 순차 번호는 델타 인코딩과 비트 패킹으로 포스팅 리스트를 압축하기 좋지만, 세그먼트마다 번호가 독립적이라 결국 포스트그레스가 이해하는 물리적 위치, 즉 ctid로 되돌리는 별도의 매핑 구조가 필요하다. ParadeDB와 pg_textsearch는 이 매핑을 유지하며, 검색이 1천만 행에 매칭되면 1천만 번의 변환 조회를 해야 한다.

TIN은 이 과정을 통째로 생략한다. 문서 식별자로 포스트그레스의 ctid를 그대로 쓰기 때문이다. ctid는 튜플의 물리적 위치를 가리키는 48비트 값으로, 상위 32비트가 페이지 번호, 하위 16비트가 페이지 내 오프셋을 나타낸다. 문제는 이런 불연속 48비트 숫자에는 기존 압축 기법이 잘 통하지 않는다는 점인데, TIN은 페이지 특성을 활용한 2단계 비트맵 인코딩으로 이를 해결한다. 8KB 페이지에는 튜플이 최대 291개, TEXT 컬럼이 섞인 스키마에서는 흔히 32개 이하만 들어가므로, 페이지 번호 목록도 페이지 내 오프셋 목록도 비트맵으로 촘촘하게 표현할 수 있다. 그 결과 고빈도 단어는 포스팅당 1비트에 근접하고, 중빈도는 약 7비트, 희귀 단어는 25비트 수준으로 저장된다.

실무자가 눈여겨볼 지점과 한계

페이지 단위 비트맵은 256비트로 x86 CPU의 AVX2·AVX-512 벡터 레지스터에 정확히 맞아떨어진다. 덕분에 교집합과 합집합은 벡터 레지스터 위의 AND·OR 명령으로, 개수 집계는 POPCNT 명령으로 처리돼 값비싼 루프와 분기를 대부분 피한다. COUNT 합집합 질의에서는 인덱스 메타데이터에 저장된 정확한 포스팅 수를 활용해, 두 단어의 페이지 비트맵이 겹치지 않으면 포스팅 리스트를 읽지 않고 개수를 합산하기도 한다. 질의당 디스크에서 읽는 데이터량(MB/query)이 작다는 점은 단순히 검색이 빠른 것을 넘어, 같은 서버의 다른 질의가 블록 캐시와 I/O를 덜 뺏겨 함께 빨라진다는 실무적 이점으로 이어진다.

다만 이 수치들은 개발사가 직접 설계·측정한 벤치마크라는 점을 감안해 읽어야 한다. 단일 EC2 인스턴스에서 복제나 운영 부하를 배제하고, 인덱스 빌드 단계에서는 경쟁 엔진에 한해 메모리를 늘려주는 등 조건이 통제돼 있어 실제 프로덕션 환경과는 차이가 있을 수 있다. 경쟁 제품들이 여러 시나리오를 완주하지 못했다는 사실 역시 각 엔진의 설계 목표가 다르기 때문일 여지가 있다. 그럼에도 ctid를 1급 시민으로 삼아 포스트그레스 내부 구조와 마찰 없이 맞물리게 한 설계 방향은, 전문검색을 별도 검색엔진으로 분리하지 않고 포스트그레스 안에서 해결하려는 팀에게 검토할 가치가 있는 선택지다. 도입을 고려한다면 자신의 코퍼스와 질의 패턴으로 동일한 인스턴스 조건에서 재현 검증해보는 것이 가장 확실한 판단 근거가 될 것이다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://planetscale.com/blog/introducing-tin
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기
처리 중...