~/tools / 임베딩과 검색(RAG) / pgvector SQL Builder

pgvector SQL Builder — pgvector SQL 작성: 테이블, HNSW/IVFFlat 인덱스, 최근접 이웃 쿼리

PostgreSQL에서 pgvector로 임베딩을 저장하고 검색하는 SQL을 작성합니다. vector(n) 또는 halfvec(n) 열이 있는 테이블, 거리에 맞는 연산자 클래스를 쓰는 HNSW 또는 IVFFlat 인덱스, 읽기 쉬운 점수를 돌려주는 최근접 이웃 쿼리를 얻을 수 있습니다. pgvector 문서에 나온 한계를 확인하고, 벡터가 차지하는 공간도 추정합니다. 데이터는 브라우저 밖으로 나가지 않습니다.

벡터 하나가 1,544바이트이므로, 10,000행이면 벡터만으로 약 15.4 MB입니다(인덱스와 다른 열은 포함하지 않음).

1. 확장과 테이블

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE documents (
  id bigserial PRIMARY KEY,
  content text NOT NULL,
  embedding vector(384) NOT NULL
);

2. 인덱스

CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);

3. 검색

PREPARE는 /api/embed로 얻은 질문의 벡터를 $1로 받습니다. '[0.01,-0.02,…]'처럼 텍스트로 전달하세요.

PREPARE search_documents(vector(384)) AS
  SELECT id, content, 1 - (embedding <=> $1) AS cosine_similarity
  FROM documents
  ORDER BY embedding <=> $1
  LIMIT 5;

-- EXECUTE search_documents('[0.0123, -0.0456, ...]');

한계와 기본값은 pgvector 0.8.7 README와 소스 코드에서 가져왔으며, 2026-11-04에 확인했습니다. pgvector README

모든 처리는 브라우저에서 이루어집니다. 이 도구는 SQL을 작성할 뿐 어디에도 연결하지 않습니다.

pgvector는 PostgreSQL에 벡터 유사도 검색을 더해 주는 오픈 소스 확장으로, Ollama로 만든 임베딩을 나머지 데이터와 같은 데이터베이스에 저장할 수 있습니다. 헷갈리기 쉬운 부분이 몇 가지 있습니다. 열의 차원 수는 임베딩 모델의 차원 수와 같아야 합니다. 거리마다 자기 연산자가 있어서, 코사인 거리는 <=>, L2 거리는 <->, 내적에 음수를 취한 값은 <#>, L1 거리는 <+>입니다. 근사 인덱스는 같은 거리의 연산자 클래스(<=>에는 vector_cosine_ops 등)로 만들었고, 쿼리가 연산자 자체를 오름차순으로 정렬하며 LIMIT이 있을 때만 사용됩니다. 이 도구는 한 번의 선택으로 세 부분을 작성합니다. CREATE EXTENSION과 CREATE TABLE, CREATE INDEX, 그리고 읽기 쉬운 점수와 함께 가장 가까운 행을 돌려주는 PREPARE 문입니다(코사인 유사도는 1에서 코사인 거리를 뺀 값이고, 내적은 <#>에 -1을 곱한 값입니다). pgvector 0.8.7의 README와 소스 코드에 있는 한계를 적용합니다. 한 열은 최대 16,000차원, 인덱스는 vector가 2,000차원, halfvec가 4,000차원까지이고, IVFFlat에는 L1 연산자 클래스가 없으며, HNSW의 m은 2에서 100까지, ef_construction은 4에서 1,000까지이면서 2 × m 이상이어야 합니다. HNSW에서는 검색이 돌려주는 행이 최대 hnsw.ef_search개(기본값 40)이므로, LIMIT이 그보다 크면 경고합니다. IVFFlat에서는 README의 시작점인 100만 행까지는 rows / 1000, 그보다 많으면 sqrt(rows), probes에는 sqrt(lists)를 써서 lists와 probes를 채웁니다. 생성된 SQL은 Ollama에서 만든 실제 384차원 벡터로 PostgreSQL 16의 pgvector 0.8.7에서 실행했고, EXPLAIN으로 인덱스가 쓰이는 것을 확인했습니다.

이 도구의 핵심 로직은 MIT 라이선스의 오픈 소스로 공개되어 있습니다. github.com/seigo5555/toolkitbox-lib/src/pgvector-sql.ts

이럴 때 사용

  • Ollama의 임베딩을 PostgreSQL에 적재하기 전에 문서 청크를 담을 테이블 만들기
  • 코사인, L2, 내적, L1 거리에서 어떤 연산자가 어떤 연산자 클래스와 짝인지 확인해 인덱스가 실제로 쓰이게 하기
  • 작은 VPS에서 벡터가 차지하는 공간을 추정하고 vector와 halfvec 비교하기

사용법

  1. 테이블 이름과 임베딩 모델의 차원 수를 입력합니다. 차원 수는 /api/embed가 돌려주는 벡터 하나의 길이이며, 이 사이트의 Embedding Similarity Calculator에서 볼 수 있습니다.
  2. 타입, 거리, 인덱스를 고릅니다. Ollama 문서는 대부분의 시맨틱 검색에 코사인 유사도를 권하며, /api/embed는 길이 1인 벡터를 돌려줍니다.
  3. 세 블록을 복사해 psql이나 다른 클라이언트에서 실행합니다. IVFFlat 인덱스는 데이터를 적재한 뒤에 만들고, HNSW 인덱스는 빈 테이블에도 만들 수 있습니다.

FAQ

어떤 거리를 골라야 하나요?

Ollama의 임베딩 문서는 대부분의 시맨틱 검색에 코사인 유사도를 권합니다. pgvector에서 <=>는 코사인 거리를 돌려주고, 이 도구는 1에서 거리를 빼서 cosine_similarity로 바꿉니다. /api/embed가 돌려주는 것처럼 길이가 1인 벡터에서는 L2 거리의 제곱이 2에서 코사인 유사도의 2배를 뺀 값이므로, 코사인 거리, L2 거리, 내적 모두 행의 순서가 같습니다.

HNSW와 IVFFlat 중 무엇이 좋나요?

pgvector README에 따르면 HNSW는 (속도와 재현율의 균형 면에서) IVFFlat보다 쿼리 성능이 좋지만 빌드가 느리고 메모리를 더 쓰며, 학습 단계가 없으므로 빈 테이블에도 만들 수 있습니다. IVFFlat은 빌드가 빠르고 메모리를 덜 쓰며, 테이블에 데이터가 어느 정도 들어간 뒤에 만들어야 합니다. 인덱스가 없으면 pgvector는 정확한 검색을 하며 완벽한 재현율을 제공합니다.

쿼리가 인덱스를 쓰지 않는 이유는 무엇인가요?

README에 따르면 쿼리에 ORDER BY와 LIMIT이 있어야 하고, ORDER BY는 1 - (embedding <=> …) DESC 같은 식이 아니라 거리 연산자 자체를 오름차순으로 써야 합니다. 연산자는 인덱스의 연산자 클래스와도 맞아야 합니다. <=>에는 vector_cosine_ops, <->에는 vector_l2_ops, <#>에는 vector_ip_ops, <+>에는 vector_l1_ops입니다. 이 도구는 하나의 선택에서 둘 다 작성합니다. README는 테이블이 작으면 테이블 스캔이 더 빠를 수 있다고도 적습니다.

LIMIT보다 적은 행이 나오는 이유는 무엇인가요?

HNSW에서는 결과 수가 hnsw.ef_search로 제한되며 기본값은 40입니다. 200행짜리 테이블에서 LIMIT 100을 시도했을 때, hnsw.ef_search를 100으로 올리기 전까지는 40행이 나왔습니다. README에 따르면 WHERE 필터링은 인덱스를 스캔한 뒤에 적용되므로 조건에 따라 행이 더 줄어들 수 있습니다. 버전 0.8.0부터는 반복 인덱스 스캔(SET hnsw.iterative_scan = strict_order 또는 relaxed_order)이 필요할 때 인덱스를 더 스캔합니다.

halfvec는 무엇인가요?

반정밀도 벡터 타입입니다. 벡터 하나가 4 × 차원 수 + 8바이트 대신 2 × 차원 수 + 8바이트를 차지하고, halfvec의 HNSW와 IVFFlat 인덱스는 2,000차원 대신 4,000차원까지 지원합니다. 각 요소가 반정밀도 부동소수점 수이므로 값이 덜 정밀하게 저장됩니다.

내 데이터가 어딘가로 전송되나요?

아니요. 이 도구는 브라우저에서 SQL만 작성하며 데이터베이스에 연결하지 않습니다.

관련 글

관련 도구