얼마 전에 새 RAG 파이프라인을 설계할 일이 있었다. 기존에 운영하던 시스템은 PostgreSQL에 pgvector를 얹어서 벡터 검색까지 한 곳에서 처리하는 구조였다. 그런데 이번에는 검색 정확도 요구사항이 더 높았고, 팀 내부에서 “Qdrant로 가야 하지 않냐”는 의견이 나왔다. 그래서 결국 둘 다 직접 붙여보고 비교하게 됐다.
이 글은 그 과정에서 겪은 걸 정리한 글이다. 어느 쪽이 “더 좋다”는 결론을 내리려는 게 아니다. 두 개를 실제로 운영해보면 어떤 상황에서 뭐가 막히는지, 그 디테일을 공유하려는 거다. 벡터DB 비교 글은 검색하면 차고 넘치지만, 대부분 스펙 표 비교다. 직접 RAG 파이프라인에 박아넣고 운영한 경험은 또 다른 이야기다.
처음 PostgreSQL + pgvector로 시작한 이유
처음 이 시스템을 설계할 때 pgvector를 택한 이유는 단순했다. 이미 운영 중인 PostgreSQL이 있었다. 사용자 데이터, 로그, 메타데이터가 다 거기 있었다. 벡터 검색을 위해 별도의 DB를 또 띄우고 운영하는 게 부담스러웠다.
pgvector는 PostgreSQL 확장이라서 설치도 간단하다. CREATE EXTENSION vector 한 줄이면 끝난다. 기존 SQL 쿼리에 벡터 컬럼을 추가하고, 코사인 유사도로 정렬하면 벡터 검색이 동작한다. 메타데이터 필터링도 그냥 SQL WHERE 절이다. 이게 제일 큰 매력이었다. 새로운 쿼리 언어를 배울 필요가 없고, 기존 ORM이나 마이그레이션 도구를 그대로 쓸 수 있다.
실제로 처음 몇 달은 이걸로 충분했다. 문서 수가 수십만 건 수준일 때는 pgvector의 HNSW 인덱스로도 응답 속도가 나쁘지 않았다. 하이브리드 검색도 직접 구현했다. BM25 점수는 PostgreSQL의 tsvector와 ts_rank로 처리하고, 벡터 유사도는 pgvector로 처리한 다음, 두 점수를 애플리케이션 레벨에서 합쳐서 재정렬하는 방식이었다.
문제가 시작된 지점 – 하이브리드 검색의 한계
문제는 검색 정확도를 더 끌어올리려고 할 때 나타났다. BM25 점수와 코사인 유사도 점수를 어떻게 합칠 것인가가 생각보다 까다로운 문제였다.
처음에는 단순하게 두 점수에 가중치를 곱해서 더하는 방식을 썼다. 그런데 두 점수의 분포 자체가 다르다. BM25 점수는 문서 길이와 단어 빈도에 따라 범위가 들쭉날쭉하고, 코사인 유사도는 0~1 사이로 고정돼 있다. 단순 선형 결합으로는 두 점수를 같은 좌표계에 놓고 비교할 수가 없었다. 정규화를 이리저리 시도했지만 어떤 쿼리에서는 BM25가 압도하고, 어떤 쿼리에서는 벡터 점수가 압도하는 식으로 결과가 불안정했다.
이 부분에서 RRF(Rank Reciprocal Fusion)라는 방법을 알게 됐다. 점수 자체를 합치는 게 아니라, 각 검색 방식에서의 “순위”를 기준으로 합치는 방식이다. 이게 훨씬 안정적이었다. 그런데 이걸 PostgreSQL에서 직접 구현하려면 두 번의 쿼리를 따로 실행해서 결과를 애플리케이션에서 합치고 재정렬하는 로직을 다 짜야 한다. 코드량이 늘어나고, 쿼리 두 번 날리는 만큼 레이턴시도 늘어난다.
Qdrant로 옮겨서 느낀 차이
이 시점에 Qdrant를 테스트 환경에 띄워봤다. 가장 먼저 체감한 건 하이브리드 검색이 “기능”으로 내장돼 있다는 점이었다. Dense 벡터(시맨틱)와 Sparse 벡터(BM25 계열)를 하나의 쿼리에서 동시에 던지고, Qdrant가 내부적으로 두 결과를 prefetch해서 RRF로 합쳐준다. 내가 애플리케이션 레벨에서 짜야 했던 점수 결합 로직이 통째로 사라졌다.
코드량으로 보면 체감이 확 온다. PostgreSQL에서는 BM25 쿼리, 벡터 쿼리, 결과 병합, 재정렬까지 거의 100줄 가까운 로직이 있었는데, Qdrant의 Query API로 옮기니까 쿼리 하나로 줄었다. 게다가 ColBERT 기반 reranking까지 같은 파이프라인 안에서 처리할 수 있어서, 별도의 reranker 모델 호출 로직도 덜어낼 수 있었다.
검색 품질도 체감상 좋아졌다. 특히 “정확한 키워드 + 의미적 맥락”이 둘 다 중요한 쿼리에서 차이가 났다. 예를 들어 “2025년 4분기 매출 관련 리스크 요인”처럼 특정 시점(키워드)과 의미(리스크 요인)가 같이 들어간 질문에서, Qdrant 하이브리드 검색의 결과가 더 안정적으로 상위에 잡혔다.
그런데 인프라가 하나 더 늘었다
좋은 이야기만 하면 또 광고가 된다. Qdrant로 옮기면서 생긴 진짜 비용은 운영 복잡도다.
이전에는 PostgreSQL 하나만 모니터링하면 됐다. 백업도 PostgreSQL 백업 정책 하나로 끝났다. Qdrant를 추가하면서 컨테이너가 하나 늘었고, 헬스체크, 백업, 버전 업그레이드를 다 따로 관리해야 한다. 그리고 데이터 동기화 문제가 새로 생겼다. 문서 메타데이터는 PostgreSQL에 있고, 벡터와 인덱스는 Qdrant에 있다. 문서를 업데이트하거나 삭제할 때 두 시스템을 모두 건드려야 하고, 둘 사이에 불일치가 생기면 디버깅이 까다롭다.
내가 겪은 실제 사례를 들면, 한 번은 문서 삭제 로직에서 PostgreSQL 쪽 레코드는 지워졌는데 Qdrant 쪽 벡터는 남아있던 적이 있었다. 그 결과 검색 결과에 이미 삭제된 문서가 계속 나타났다. 트랜잭션이 두 시스템에 걸쳐 있다 보니, 한쪽만 성공하고 한쪽이 실패하는 상황에 대한 보상 로직을 따로 만들어야 했다. PostgreSQL 하나만 쓸 때는 이런 문제 자체가 존재하지 않았다.
그래서 지금 어떤 기준으로 선택하나
직접 둘 다 운영해보고 나서 내가 세운 기준은 이렇다.
문서 규모가 수십만 건 이하이고, 검색 요구사항이 “어느 정도 괜찮은 수준”이면 pgvector로 충분하다. 이미 PostgreSQL을 쓰고 있다면 새 인프라를 추가하지 않는 것 자체가 큰 이점이다. 운영 인력이 적은 팀일수록 이 단순함의 가치가 크다.
반면 검색 품질이 제품의 핵심 경쟁력이거나, 문서 규모가 수백만 건을 넘어가거나, 하이브리드 검색과 reranking을 정교하게 튜닝해야 하는 상황이면 Qdrant 쪽이 맞다. 특히 법률, 금융처럼 정확한 키워드 매칭과 의미 검색이 둘 다 정밀해야 하는 도메인에서는 Qdrant의 필터링과 하이브리드 검색 구조가 확실히 유리하다.
내가 최종적으로 선택한 방식은 둘을 같이 쓰는 거였다. 사용자 데이터와 메타데이터, 로그는 여전히 PostgreSQL에 두고, 검색이 핵심인 RAG 인덱스만 Qdrant로 분리했다. 모든 걸 한쪽으로 몰아넣으려고 하지 않는 게 오히려 더 깔끔했다.
마이그레이션할 때 진짜 고민해야 하는 것
pgvector에서 Qdrant로 옮기기로 했다면, 가장 먼저 고민할 건 동기화 전략이다. 처음부터 “PostgreSQL이 원본(source of truth)이고 Qdrant는 검색 인덱스”라는 역할 분리를 명확히 해야 한다. 문서가 생성되거나 수정되면 PostgreSQL에 먼저 쓰고, 그다음 Qdrant 인덱스를 업데이트하는 순서를 일관되게 지켜야 한다. 이 순서가 흔들리면 앞서 말한 동기화 불일치가 반복된다.
그리고 sparse 벡터 생성 파이프라인도 새로 필요하다. BM25 계열의 sparse 임베딩을 만드는 과정이 dense 임베딩과는 별도로 들어간다. 기존에 dense 임베딩만 만들던 파이프라인이라면 이 부분을 추가로 설계해야 한다.
마지막으로, 작은 규모에서 먼저 A/B 테스트를 해보는 걸 추천한다. 전체 인덱스를 한꺼번에 옮기지 말고, 일부 쿼리 세트에 대해 pgvector 결과와 Qdrant 하이브리드 결과를 나란히 비교해보면 실제로 품질이 얼마나 개선되는지 체감할 수 있다. 이 체감 없이 인프라만 옮기면, 복잡도만 늘고 효과는 못 느끼는 상황이 생길 수 있다.
도구가 아니라 데이터 규모와 팀 역량의 문제
결국 이건 “어떤 벡터DB가 더 좋은가”의 문제가 아니다. 우리 팀의 데이터 규모, 검색 품질에 대한 요구 수준, 그리고 인프라를 추가로 운영할 여력이 있는가의 문제다.
pgvector는 “이미 있는 것을 최대한 활용한다”는 철학이고, Qdrant는 “검색이라는 문제를 전문적으로 푼다”는 철학이다. 둘 다 맞는 선택이 될 수 있다. 다만 어느 쪽을 택하든, 한 번 운영을 시작하면 되돌리기가 쉽지 않다는 점은 분명히 알고 시작해야 한다. 나처럼 둘 다 운영해보고 나서야 “이게 우리 상황에 맞는 선택이었나”를 다시 고민하게 되는 경우도 있으니까.