거의 모든 검색 시스템은 이미 운영 중인 Postgres 위의 pgvector로 시작해야 하며, 선택의 질문은 "어느 벡터 데이터베이스가 가장 빠른가"가 아니라 "어떤 실패 모드가 나에게 먼저 닥치는가"다. 공개된 recall과 QPS 수치는 대부분의 팀이 실제로 운영하는 규모에서 엔진 간에 수렴한다. 수렴하지 않는 것은 모든 쿼리에 테넌트 필터를 붙일 때, 업무 시간 중에 인덱스를 재빌드해야 할 때, HNSW 그래프가 더 이상 RAM에 들어가지 않을 때 벌어지는 일이다. 마이그레이션을 강제하는 것은 바로 이런 사건들이고, 엔진마다 무너지는 지점이 다르다.

그래서 벡터 스토어를 정직하게 비교하는 방법은 깨지는 지점에서 거꾸로 접근하는 것이다. 가장 먼저 맞닥뜨릴 실패를 고르고, 그 실패가 없는 엔진을 고르면 된다. 나머지는 전부 기능 비교표에 불과하다.

실제로 깨지는 네 가지

프로덕션 RAG와 에이전트 메모리 시스템을 통틀어, 처음 선택한 엔진을 떠나는 마이그레이션의 거의 전부는 다음 네 가지 증상에서 비롯된다:

  • 인덱스 빌드와 재빌드 시간. 임베딩 모델이나 차원 수, 거리 연산자를 바꾸면 모든 행에 대해 근사 최근접 이웃 인덱스를 다시 빌드해야 한다. 100만 개 벡터에서는 커피 한 잔이면 끝난다. 5,000만 개에서는 유지보수 윈도우가 필요하고, 새 인덱스가 빌드되는 동안 기존 인덱스로 트래픽을 받을지 결정해야 한다.
  • 필터가 걸린 검색의 recall. 프로덕션에서 필터 없는 벡터 쿼리를 돌리는 곳은 거의 없다. 실제 쿼리는 "where tenant_id = X and status = active and updated_at > Y 조건의 최근접 이웃"이다. 그래프 인덱스는 필터 없는 경우를 위해 설계되어 있어서, 선택도가 높은 필터가 걸리면 ANN 검색이 요청한 k개보다 적은 행을 조용히 반환할 수 있다. 관련성 문제처럼 보이지만 실체는 정확성 문제다.
  • 그래프 메모리 대 RAM. HNSW는 그래프이고, 메모리에 상주하고 싶어 한다. 그래프와 워킹 셋의 합이 인스턴스 메모리를 넘어서는 순간 지연 시간은 완만하게 나빠지지 않는다. 머신이 프로브마다 디스크에서 인덱스 페이지를 읽기 시작하면서 절벽에서 떨어지듯 무너진다.
  • 쓰기 부하에서의 최신성 지연. 에이전트 메모리와 지원 도구는 끊임없이 쓴다. 삽입마다 그래프가 변형되고, 인덱스 유지보수가 쿼리 트래픽과 경쟁하며, "사실을 저장했다"와 "그 사실이 검색된다" 사이의 간격이 느낌의 문제가 아니라 정확성의 문제가 되기 시작한다.

이 목록에 없는 것에 주목하라: 순수한 초당 쿼리 수다. 검색 결과를 받은 모델이 생성에 2초를 쓰는 구조라면, 검색 지연 10밀리초 차이는 노이즈다. The latency that hurts in RAG lives in the number of round trips에서 썼듯이, RAG에서 아픈 지연은 ANN 프로브가 아니라 왕복 횟수에 있다.

pgvector: 올바른 기본값, 그리고 진짜 한계

pgvector를 쓰는 근거는 벤치마크 승리가 아니다. 임베딩이 자신이 설명하는 행과 같은 트랜잭션 안에 살고, 필터는 이미 인덱스가 있는 컬럼에 대한 평범한 SQL이며, 백업과 시점 복구는 이미 운영하는 그 절차 그대로이고, 온콜 담당자는 이미 EXPLAIN을 읽을 줄 안다. 이 조합은 상당한 p99과 맞바꿀 가치가 있다.

한계는 구체적이고 외워둘 가치가 있다. 한계 자체보다 그것에 대한 막연한 두려움이 성급한 마이그레이션을 더 많이 일으키기 때문이다:

  • 차원 제한은 인덱스 제한이지 컬럼 제한이 아니다. vector 컬럼은 최대 16,000차원을 받지만, HNSW와 IVFFlat은 2,000차원까지만 인덱싱한다. halfvec(16비트 부동소수점)을 쓰면 대략 절반의 저장 공간으로 4,000차원까지 인덱싱한다. bit는 이진 양자화로 64,000차원까지, sparsevec은 0이 아닌 원소 1,000개까지 처리한다. 3,072차원 임베딩은 Postgres를 떠날 이유가 아니라 인덱스 표현식에서 halfvec으로 캐스팅할 이유다.
  • 필터 쿼리의 절벽은 0.8.0에서 사라졌다. 예전의 실패는 실재했다: HNSW 스캔이 ef_search개의 후보를 반환하고 WHERE 절이 그 대부분을 걸러내면, 10개를 요청했는데 3개만 돌아왔다. pgvector 0.8.0이 반복 인덱스 스캔을 추가했고, 살아남는 행이 충분해질 때까지 스캔을 이어간다. hnsw.iterative_scan = strict_order는 정확한 거리 순서를 유지하고, relaxed_order는 순서를 약간 양보하는 대신 recall을 높인다. pgvector의 필터링에 대한 인식이 2024년에 머물러 있다면 이미 낡은 것이다.
  • 실제로 무는 것은 빌드 메모리다. HNSW는 그래프가 maintenance_work_mem 안에 들어가면 메모리에서 빌드하고, 넘치면 훨씬 느린 디스크 경로로 떨어진다. 해결책은 빌드 동안 값을 올리고 병렬 워커를 쓰는 것이지만, 어느 크기를 넘어서면 재빌드를 실행하는 것이 아니라 계획해야 하는 단계에 들어선다.
  • 시끄러운 이웃 문제는 아키텍처 문제다. 결제 흐름을 서빙하는 인스턴스에서 ANN 빌드가 CPU를 포화시키는 것은 벡터와 무관한 실패 모드다. 읽기 복제본이나 별도 인스턴스가 해결해 주지만, 그 순간부터 pgvector는 더 이상 공짜가 아니다.

AWS로 한정하면, pgvector를 얹은 Aurora PostgreSQL은 일급 Bedrock Knowledge Bases 벡터 스토어라서, 이 선택으로 관리형 RAG 기능을 잃는 것은 없다. 비용 측면은 the OpenSearch Serverless to Aurora migration post에 정리해 두었는데, 아래에 단서가 하나 있다: 그 비교의 OpenSearch 쪽 사정이 2026년 5월에 바뀌었다.

OpenSearch: 검색 엔진을 사는 것이니, 검색 엔진으로 써라

순수 벡터 스토어 용도로만 OpenSearch를 고르는 것은 벡터 검색을 가장 비싸게 얻는 방법이다. 검색이 필요하고 벡터가 그 검색 수단 중 하나라서 고르는 것은 전혀 다른, 훨씬 나은 결정이다.

순수 벡터 스토어가 주지 못하는 것을 준다: ANN 옆에 나란히 놓인 진짜 lexical 검색. BM25와 벡터 유사도를 결합하는 하이브리드 검색이 아키텍처가 아니라 쿼리 하나로 끝난다. 임베딩이 유난히 약한 부품 번호, 에러 코드, 식별자에 대한 정확한 키워드 매칭. 나중에 덧붙인 것이 아니라 고카디널리티 속성을 위해 설계된 집계, 패싯, 필터링 엔진. 그리고 이진 벡터: Bedrock Knowledge Bases에서는 두 가지 OpenSearch 옵션만 이를 지원한다.

반대 논거는 역사적으로 바닥 비용이었다: OpenSearch Serverless는 OCU 단위로 과금되고 프로덕션 최소치가 있어서 문서 하나 인덱싱하기 전부터 실제 돈이 나갔다. 내 마이그레이션 글이 그 논거 위에 서 있었고, 이제 정정이 필요하다. 차세대 OpenSearch Serverless가 2026년 5월 28일 정식 출시되었다. 컴퓨트와 스토리지가 완전히 분리되고, scale-to-zero를 지원하며, AWS 표현으로는 이전 세대보다 20배 빠른 오토스케일링을 갖췄다. AWS는 피크 부하 기준으로 클러스터를 프로비저닝하는 것 대비 최대 60퍼센트 절감을 주장한다. 워크로드가 순간적으로 튀는 형태라면, 그리고 에이전트 기반 검색은 극도로 그런 형태인데, 내가 펼쳤던 형태의 바닥 비용 논거는 더 이상 성립하지 않는다.

여전히 깨지는 것: 샤드, 복제본, 클러스터 상태를 가진 분산 시스템이고, 언젠가는 셋 모두를 고민하게 만든다. 벡터 워크로드의 샤드 크기 산정은 로그의 그것과 같지 않다. 그리고 재빌드는 곧 reindex이고, 이는 인덱스 두 벌 분량의 용량 계획을 뜻한다.

S3 Vectors: 쿼리에 답하는 스토리지 계층이지 서빙 계층이 아니다

S3 Vectors는 2025년 12월 2일, 프리뷰의 40배 규모로 정식 출시되었다. 인덱스당 최대 20억 벡터, 벡터 버킷당 인덱스 1만 개이며, 2026년 3월에 17개 리전이 추가되었다. AWS는 벡터 데이터베이스 운영 대비 최대 90퍼센트의 비용 절감을 내세우는데, 그 이유는 홍보성이 아니라 구조적이다: 클러스터도, 프로비저닝된 컴퓨트도, 유휴 요금도 없다.

적합 여부를 가르는 숫자는 지연 프로파일이다. AWS 문서에 따르면 드문 쿼리는 1초 미만, 더 잦은 쿼리는 대략 100밀리초 이하로 돌아온다. 이것을 웜 캐시 효과로 읽고, 자신의 트래픽에 솔직해져라: 시간당 40개의 질문을 받는 지원 어시스턴트는 아무것도 데워두지 못한다. 1초 미만은 야간 요약 잡에는 충분하지만, 모델이 자기 몫의 2초를 또 써야 하는 대화형 챗에는 틀린 답이다.

진짜로 맞는 자리: 콜드 또는 아카이브 벡터 계층, 테넌트 수는 많고 테넌트별 트래픽은 희박한 테넌트별 인덱스, 지연 예산이 관대한 비용 우선 Bedrock Knowledge Bases, 그리고 대안이 유휴 클러스터 비용 지불이었던 모든 경우. 핫 스토어 아래의 2차 계층으로 잘 조합되며, 전면 교체가 아니라 그렇게 쓰는 것이 내 방식이다.

Qdrant, Milvus, Pinecone: 페이로드가 이기는 순간

벡터 워크로드가 애플리케이션의 기능 하나이기를 멈추고 애플리케이션 그 자체가 되었을 때 Postgres를 떠나 전용 엔진으로 간다. 그 형태는 세 가지다:

Qdrant는 필터링이 문제일 때 잡는 엔진이다. 페이로드 인덱스와 필터링 가능한 HNSW는 pgvector의 반복 스캔이 겨우 버텨내는 상황, 즉 모든 쿼리에 걸리는 선택도 높은 필터를 높은 빈도로 처리하도록 설계되어 있다. 스칼라, 프로덕트, 이진 양자화도 함께 제공하는데, 큰 인덱스를 메모리에 상주시키는 현실적인 방법이 바로 이것이다. 읽기마다 테넌트별 필터가 걸리는 멀티테넌트 에이전트 메모리 스토어라면, 데이터베이스를 하나 더 운영할 방어 가능한 이유가 된다.

Milvus는 10억 규모의 답이다. 디스크 기반 인덱싱(DiskANN) 덕분에 워킹 셋이 RAM에 다 들어갈 필요가 없고, 그 규모에서 하드웨어 청구서를 바꾸는 것이 바로 이 점이다. 대가는 운영이다: 코디네이터, 쿼리, 데이터, 인덱스 역할이 분리된 분산 시스템이고, 프로덕션에서 돌리는 일은 기술적 결정이기 이전에 인력 배치 결정이다. 수억 벡터 아래에서는 그 복잡성이 사주는 것이 거의 없다.

Pinecone은 만들지 않고 사는 선택지이고, 다른 SaaS를 평가하듯 평가해야 한다: 지연이 아니라 덜어주는 운영 부담으로. 서버리스 과금은 스토리지를 읽기와 쓰기에서 분리하고 유휴 비용이 없어서, 순간적으로 튀는 워크로드에 맞고 소규모 배포를 진짜로 싸게 만든다. 포기하는 것은 실패 모드에 대한 통제이고, 이그레스 비용과 벤더 결합을 떠안는다. Bedrock Knowledge Bases가 지원하는 스토어이기도 해서, AWS 관리형 RAG 경로에서 이탈하는 것도 아니다.

롱테일, 짧게

Weaviate는 배터리 포함형 RAG 스토어에 가장 가까운 물건이다: 내장 벡터화 모듈, 하이브리드 검색, 스키마 우선 모델. 의견이 정해진 도구를 원한다면 매력적이고, 이미 임베딩 파이프라인이 있다면 덜하다. Chroma는 스스로 프로토타이핑 도구임을 숨기지 않는 프로토타이핑 도구이고, 내가 본 진지한 배포는 결국 전부 다른 곳으로 옮겨갔다. Redis의 벡터 유사도는 벡터가 휘발성일 때, 즉 세션, 단기 에이전트 메모리, 시맨틱 캐시에는 훌륭하고, 시스템 오브 레코드로는 끔찍하다. MongoDB Atlas Vector Search와 Mongo의 관계는 pgvector와 Postgres의 관계와 같다: 문서가 이미 거기 산다면 맞는 선택이고, 아니라면 Mongo를 도입할 빈약한 이유다. Redis Enterprise Cloud와 MongoDB Atlas 둘 다 Bedrock Knowledge Bases가 지원하는 스토어다.

결정 테이블

엔진최적 지점먼저 깨지는 것운영 주체
pgvector약 5,000만 벡터 이하, 필터는 SQL, 데이터가 이미 Postgres에 있음인덱스 빌드 메모리와 재빌드 윈도우, OLTP와 경쟁하는 ANN기존 DBA와 온콜
OpenSearchlexical과 벡터의 하이브리드, 패싯, 이진 벡터샤드와 클러스터 상태 관리, reindex 용량검색 클러스터를 아는 사람
S3 Vectors콜드 계층, 희박한 테넌트별 인덱스, 비용 우선 Knowledge Bases드물게 조회되는 인덱스의 대화형 지연아무도 없음, 그것이 핵심
Qdrant모든 쿼리에 걸리는 선택도 높은 필터, 양자화된 상주 인덱스스테이트풀 시스템을 하나 더 운영하게 됨직접, 또는 Qdrant Cloud
Milvus약 5억 벡터 이상, 디스크 기반 인덱싱다중 역할 분산 시스템의 운영 표면적전담 플랫폼 엔지니어
Pinecone튀는 트래픽, 스테이트풀 운영에 대한 의사 없음지속적 대용량에서의 비용 곡선, 벤더 결합Pinecone

"지금 pgvector를 떠나라"를 실제로 뜻하는 트리거

추상적인 규모가 아니다. 이것들이다:

  • HNSW 재빌드가 더 이상 허용 가능한 유지보수 윈도우에 들어가지 않고, maintenance_work_mem도 이미 올렸고 병렬 워커도 이미 썼다.
  • 반복 스캔을 켜고 ef_search를 튜닝한 뒤에도 필터 recall이 여전히 모자란다. 필터의 선택도가 높아서 그래프가 애초에 틀린 자료 구조이기 때문이다.
  • 인덱스 워킹 셋이 인스턴스 메모리를 넘고, 한 단계 위 인스턴스가 전용 엔진보다 비싸다.
  • 벡터 검색이 트랜잭션 워크로드를 굶기고 있고, 읽기 복제본으로는 분리가 충분하지 않다.
  • 애플리케이션 코드에서 두 검색을 병합하는 방식이 아니라, lexical과 벡터를 결합한 랭킹이 일급 쿼리로 필요하다. 이 항목은 특히 OpenSearch를 가리킨다.

이 중 어느 것도 해당하지 않는다면, 계획 중인 마이그레이션은 필요가 아니라 취향이다. 이미 운영하는 데이터베이스 위에 동작하는 검색 계층을 먼저 출시하고 트리거가 실제로 발화했을 때만 움직이는 팀이, 첫 스프린트를 고르는 데 써버린 팀보다 훨씬 먼저 프로덕션에 도달한다.

정리

pgvector로 시작하되, 네 가지 한계를 진짜 한계와 소문을 구분할 수 있을 만큼 정확히 알아두어라. 유사도가 아니라 검색이 필요해지면 OpenSearch로 옮기고, 비용 비교는 예전 OCU 바닥이 아니라 차세대 서버리스를 기준으로 다시 돌려라. S3 Vectors는 콜드 계층과 희박한 테넌트별 인덱스에 쓰고, 대화형 서빙 경로로는 쓰지 마라. 필터링이 지배하면 Qdrant, RAM이 청구서를 결정하는 지점을 넘으면 Milvus, 운영을 직접 하느니 사겠다면 Pinecone이다. 가장 먼저 맞을 깨짐을 기준으로 골라라. 이 비교에서 엔진 간에 의미 있게 다른 변수는 그것뿐이다.

이어서 읽기

프로덕션에서 Postgres와 검색 클러스터를 운영하는 인프라 쪽 이야기는 ercan.cloud의 클라우드 필드 노트에 있고, 허브는 ercanermis.com이다.

참고 자료