벡터 검색에서 가장 먼저 내려야 할 결정은 HNSW냐 IVF냐가 아니다. 시스템이 어디에 존재하느냐다. Qdrant는 전용 벡터 엔진이고, pgvector는 PostgreSQL 인덱스 접근 방식이며, LanceDB/Lance는 파일 기반 임베디드 스택이다. 이 선택이 필터링, 내구성, 일관성, 장애를 누가 책임지는지 결정한다.
이 지도를 Qdrant v1.18.2 (44ad62f8cd69642be5afa6441612525e24a0d063), pgvector v0.8.4 (1d458ad5d73731241e8b912cacc2079beb643d30), Lance v8.0.0 (15f2ff594a25b97f9bedd21a253b612ce14e39ec), LanceDB v0.30.0 (a5288de8d14ff0dfbf42a69c5e2a557b06ebfb6b) 기준으로 읽었다. 짧게 말하면 이렇다. 검색 서비스를 운영하고 싶은지, 이미 신뢰하는 데이터베이스를 확장하고 싶은지, 아니면 인덱싱된 벡터 데이터를 파일로 들고 다니고 싶은지 알기 전에는 “어떤 벡터 데이터베이스가 가장 빠른가?“라고 묻지 말아야 한다. 기대치를 미리 맞춰두자. 이 글은 소유권을 그린 지도이지 벤치마크 글이 아니다. 재현율과 지연 시간 수치는 여기서 다루지 않는다.

첫 번째 갈림길은 운영 방식이다. 서버가 소유하는 검색, Postgres가 소유하는 인덱스 접근, 또는 애플리케이션이 여는 파일이다.
한 표로 보는 비교
| 질문 | Qdrant | pgvector | LanceDB / Lance |
|---|---|---|---|
| 무엇으로 존재하는가? | 전용 벡터 엔진 | PostgreSQL 확장이자 인덱스 접근 방식 | Lance 데이터셋과 로컬/객체 스토리지 경로 위에 놓인 LanceDB 연결 계층 |
| 벡터 검색 경로를 누가 소유하는가? | Qdrant의 세그먼트 및 HNSW 플래너 | PostgreSQL의 인덱스 AM 콜백 경로와 pgvector 연산자 | 애플리케이션이 여는 Lance/LanceDB 코드 |
| 필터링은 ANN과 어디에서 만나는가? | Qdrant의 필터 적용 HNSW 디스패치와 선택적 페이로드 인식 그래프 링크 내부 | 순서 지정 벡터 인덱스 스캔을 둘러싼 Postgres 쿼리 실행 단계 | 파일 기반 데이터셋과 IVF 계열 벡터 인덱스 주변 |
| 내구성과 가시성을 누가 소유하는가? | 벡터 서비스 | PostgreSQL 릴레이션 페이지, WAL, 힙 TID, MVCC 스냅샷 | 프래그먼트 위의 Lance 버전 관리 매니페스트 |
| 핵심 운영 선택 | 목적에 맞게 만든 벡터 서비스를 운영한다 | 이미 운영 중인 데이터베이스 원장 안에 벡터를 둔다 | 벡터 데이터가 파일, 작업, 노트북, 객체 스토리지와 함께 이동하게 한다 |
이 표 때문에 벤치마크 차트를 가장 먼저 보면 오해하기 쉽다. Qdrant의 필터 적용 검색, pgvector의 ORDER BY embedding <-> query LIMIT k, Lance의 파일 기반 IVF 인덱스는 같은 곳에 영속화되거나, 필터링되거나, 배포되지 않는다.
Qdrant: 벡터 엔진이 검색과 필터링을 소유한다
이 비교에서 Qdrant의 가장 강한 주장은 단순히 “HNSW가 있다”는 것이 아니다. 흥미로운 부분은 필터 적용 검색 분기가 페이로드 필터링을 검색 계획의 일부로 만든다는 점이다.
Qdrant v1.18.2에서 필터가 적용된 HNSW 경로는 먼저 페이로드 필터의 카디널리티를 추정하고, 사용 가능한 벡터에 맞춰 그 추정치를 조정한 다음 경로를 나눈다. 필터링 결과가 작으면 일반 검색으로 간다. 결과가 크면 HNSW 그래프 검색으로 간다. 추정치만으로 결정하기 어려우면 Qdrant는 경로를 선택하기 전에 표본 카디널리티 검사를 실행한다 (vector_index_impl.rs#L114-L166).
이것이 서버 형태의 설계다. 벡터 엔진은 외부 SQL 실행기가 최종 후보 집합을 넘겨주기를 기다리지 않는다. 검색 경로 안에서 필터가 정확 검색을 쓰기에 충분히 작은지, 그래프 순회를 쓰기에 충분히 큰지를 직접 결정한다.
Qdrant에는 필터 적용 HNSW의 고전적인 문제에 대한 빌드 시점의 해법도 있다. 전체로 보면 연결된 그래프가 필터로 잘라낸 범위 안에서는 끊길 수 있다는 문제다. 조건에 맞게 인덱싱된 페이로드 필드에 대해 Qdrant는 페이로드 블록을 순회하고, 별도의 payload_m 예산으로 필터링된 하위 그래프를 추가로 만든 뒤, 그 링크를 기본 그래프 빌더에 병합할 수 있다 (build.rs#L378-L523). 코드에는 건너뛰기 휴리스틱이 있으므로 “모든 페이로드 값에 언제나 추가 링크가 생긴다”는 뜻은 아니다. 중요한 것은 소유권이다. Qdrant가 그래프를 소유하기 때문에 그래프의 형태를 바꿀 수 있다.
이렇게 생각하면 된다. 최근접 이웃 검색과 필터 적용 검색을 일급 경로로 만드는 데 필요한 만큼의 페이로드 구조를 모두 벡터 엔진이 소유해야 할 때 Qdrant를 선택한다.
pgvector: Postgres가 데이터베이스를 소유하고 pgvector가 벡터 인덱스를 더한다
pgvector는 거의 정반대의 선택이다. 새로운 벡터 서비스로 진실을 옮기라고 요구하지 않는다. 벡터 검색이 Postgres 안에 존재하게 만든다.
v0.8.4에서 pgvector는 HNSW를 PostgreSQL 인덱스 접근 방식으로 등록한다. SQL 파일은 hnswhandler(internal)를 선언하고 hnsw 접근 방식을 생성한다. 한편 C 핸들러는 IndexAmRoutine을 반환하고, 순서 지정 연산자를 지원한다고 표시하며, HNSW 빌드, 삽입, 스캔 훅을 연결한다 (vector.sql#L257-L260, hnsw.c#L266-L310). 연산자 클래스는 <->, <#>, <=> 같은 벡터 거리 연산자를 순서 지정 스캔을 위한 USING hnsw에 연결한다 (vector.sql#L313-L326).
이로써 Qdrant와는 매우 다른 계약이 생긴다. HNSW 그래프는 독립적인 스토리지 엔진이 아니라 PostgreSQL이 관리하는 인덱스 릴레이션이다. pgvector는 PostgreSQL 버퍼로 HNSW 페이지를 할당하고, HNSW 요소 튜플에 힙 TID를 저장하며, 릴레이션에 WAL이 필요하면 빌드된 인덱스 페이지를 WAL에 기록한다. 일반 삽입 변경에는 범용 WAL을 사용하고, 스캔에는 MVCC 스냅샷을 요구하며, PostgreSQL 인덱스 스캔 경로를 통해 힙 TID를 반환한다 (hnswutils.c#L184-L196, hnsw.h#L357-L367, hnswbuild.c#L1137-L1138, hnswinsert.c#L194-L195, hnswscan.c#L216-L325).
이것이 pgvector가 매력적인 진짜 이유다. Postgres를 마법처럼 전용 벡터 서비스로 바꿔서가 아니라, 벡터를 애플리케이션의 나머지 상태와 같은 백업, WAL, 스냅샷, 관계형 쿼리 체계 아래 둘 수 있기 때문이다.
절충점도 같은 사실에서 따라온다. pgvector는 Postgres 플래너와 실행기의 세계에 참여한다. 벡터 엔진 자체가 페이로드 인식 그래프 구성과 필터 적용 검색 디스패치를 소유하기 바란다면 그것은 Qdrant의 형태다. 벡터 검색을 기존 Postgres 진실 체계 안에 유지하고 싶다면 pgvector의 형태 자체가 핵심이다.
LanceDB와 Lance: 벡터 시스템이 파일과 함께 이동한다
LanceDB/Lance는 세 번째 형태다. 상주 서버나 Postgres 릴레이션이 아니라 파일 기반 임베디드 데이터 스택으로 존재하는 벡터 검색이다.
LanceDB v0.30.0의 Rust 연결 경로를 보면 이 구분이 드러난다. ConnectBuilder::execute는 db로 시작하는 URI를 원격 분기로 보내고, manifest_enabled가 설정된 로컬 네이티브 연결을 네임스페이스 데이터베이스 분기로 보내며, 원격도 아니고 매니페스트도 사용하지 않는 기본 분기를 ListingDatabase::connect_with_options로 보낸다 (connection.rs#L910-L931). 그 기본 분기는 URI에서 객체 스토어를 열고, 로컬 스토어인 경우에만 로컬 디렉터리를 생성한다 (listing.rs#L550-L560).
이 표현은 의도적으로 신중하게 골랐다. 소스로 뒷받침되는 주장은 “원격이 아닌 모든 LanceDB 연결이 ListingDatabase다”가 아니다. 검증된 분기는 더 좁다. 원격, 매니페스트를 사용하는 로컬 네임스페이스, 기본 ListingDatabase는 서로 별개의 경로다.
그 연결 계층 아래에서 Lance v8.0.0은 데이터셋 상태를 프래그먼트 위의 버전 관리 매니페스트로 저장한다. Manifest에는 프래그먼트와 버전 번호가 들어 있고, 매니페스트 경로는 _versions 아래에 있으며, 커밋은 대상이 이미 존재할 때 커밋 충돌로 매핑하는 생성 전용 이름 변경 경로를 사용한다 (table.proto#L36-L47, commit.rs#L93-L108, commit.rs#L1439-L1460).
벡터 인덱스 계열도 같은 사실을 보여준다. Lance의 벡터 인덱스 열거형은 IVF가 우선이다. IvfFlat, IvfSq, IvfPq, IvfHnswSq, IvfHnswPq, IvfHnswFlat, IvfRq가 있으며, 레거시 Vector는 IVF_PQ로 표시된다 (lance-index/src/lib.rs#L137-L169). 따라서 운영 이야기와 인덱스 이야기는 같은 방향을 가리킨다. 데이터와 인덱스 상태는 별도의 벡터 서비스 경계 뒤가 아니라 데이터셋과 함께 존재하도록 설계됐다.
벡터 검색이 로컬 파일, 객체 스토리지 데이터, 노트북, 파이프라인, 엣지 작업, 임베디드 애플리케이션 코드와 함께 이동해야 할 때 이 형태를 사용한다. 무게중심으로 파일 기반 버전 관리 데이터를 선택하는 것이다.
처음에는 HNSW와 IVF의 차이보다 이것이 더 중요한 이유
HNSW와 IVF의 차이는 중요하다. 재현율, 지연 시간, 메모리, 빌드 시간, 업데이트 동작도 모두 중요하다. 하지만 운영상의 기반을 알기 전까지는 이 모두가 부차적인 질문이다.
검색이 Qdrant 서비스로 존재한다면 필터 적용 검색을 벡터 엔진 안에서 계획할 수 있고, 조건에 맞게 인덱싱된 필드에 대해 페이로드 인식 링크를 그래프에 추가할 수 있다. 운영상 장애 영역은 서비스다.
검색이 pgvector 인덱스로 존재한다면 벡터 경로는 Postgres의 스토리지, WAL, MVCC, 쿼리 체계에 합류한다. 운영상 장애 영역은 데이터베이스다.
검색이 애플리케이션 코드가 여는 Lance/LanceDB 파일로 존재한다면 버전 관리 매니페스트와 파일/객체 스토리지 경로가 중심이 된다. 운영상 장애 영역은 데이터 배치 방식, 객체 스토어, 그리고 이를 여는 작업이나 앱이다.
이것들은 구현 세부 사항이 아니다. “일관성”이 무엇을 뜻하는지, 필터를 어디에서 최적화할 수 있는지, 어떤 백업 시스템을 신뢰하는지, 배포가 어떤 모습인지, 어느 팀이 호출을 받는지를 결정한다.
내 위치 찾기
벡터 검색 서비스가 까다로운 벡터 검색 메커니즘을 소유하기 바란다면 Qdrant를 선택한다. 내가 중요하게 보는 근거는 흔한 HNSW 체크박스가 아니라 필터 적용 검색 디스패치와 페이로드 인식 그래프 빌드 체계다.
Postgres가 이미 진실의 원천이고 그 원장 안에 벡터 검색을 두고 싶다면 pgvector를 선택한다. 실제 HNSW 접근 방식과 벡터 연산자 클래스를 얻지만, 더 깊은 이점은 인덱스가 PostgreSQL의 릴레이션, WAL, 힙 TID, MVCC 경로에 참여한다는 것이다.
벡터 검색이 상주 서비스 뒤에 머무르기보다 데이터셋과 함께 이동해야 한다면 LanceDB/Lance를 선택한다. 기본 로컬/객체 스토어 분기와 Lance의 버전 관리 매니페스트 모델은 파일을 중심에 놓고, 그 파일 기반 세계에 IVF 우선 인덱스 계열을 붙인다.
범위와 정직성
이 글은 벤치마크 글이 아니다. 여기서는 재현율, 지연 시간, 메모리, 비용을 측정하지 않았다. 소스에서 확인할 수 있는 소유권 모델을 그리는 이유는 그래야 공정한 벤치마크가 무엇을 비교해야 하는지부터 알 수 있기 때문이다.
또한 이 프로젝트들을 슬로건으로 단순화하지 않는다. Qdrant에도 정확 검색/일반 검색 경로가 있다. pgvector도 실제 HNSW를 구현한다. Lance에는 IVF-HNSW 변형이 포함된다. LanceDB에는 원격 분기가 있다. 요점은 각 프로젝트에 기능이 하나뿐이라는 것이 아니다. 각 프로젝트마다 벡터 검색이 존재하는 장소가 다르다는 것이다.
여기서 시작하면 된다. 그다음 실제로 운영하고 싶은 형태를 벤치마크하자.



