벡터 검색에서 제일 자주 부딪히는 벽이 “index가 메모리에 안 들어간다"입니다. AWS가 그 벽을 이진 양자화로 넘은 사례를 냈습니다. 1억 벡터 index가 367GB에서 약 38GB가 됐습니다.
부호만 남긴다
이진 양자화의 방식은 이름 그대로입니다. 각 차원의 float32 값을 0을 기준으로 잘라 1비트로 만듭니다. 양수면 1, 음수면 0입니다.
768차원 벡터라면 원래 768 × 4바이트 = 3,072바이트입니다. 양자화하면 768비트, 즉 96바이트입니다. 32분의 1입니다.
정보를 크게 버리는 방식인데 벡터 검색에서 통하는 이유가 있습니다. 고차원 임베딩에서는 각 차원의 정확한 크기보다 부호 패턴이 방향을 상당히 결정합니다. 768개 차원의 부호가 얼마나 겹치는지만 봐도 두 벡터가 비슷한지 대략 알 수 있습니다. 이 비교가 Hamming 거리입니다.
직접 재 봤다
pgvector 0.8.6이 들어간 PostgreSQL 18 컨테이너로 확인했습니다. 768차원 벡터 3만 개를 넣고 두 종류 index를 만들었습니다.
create table docs (id bigserial primary key, embedding vector(768));
insert into docs (embedding)
select (select array_agg(random()-0.5) from generate_series(1,768))::vector
from generate_series(1,30000);
일반 HNSW와 이진 양자화 HNSW입니다.
create index idx_full on docs
using hnsw (embedding vector_cosine_ops)
with (m=16, ef_construction=64);
create index idx_bq on docs
using hnsw ((binary_quantize(embedding)::bit(768)) bit_hamming_ops)
with (m=16, ef_construction=64);
bit_hamming_ops가 bit 타입에 Hamming 거리를 적용하는 연산자 클래스입니다. 크기를 비교했습니다.
indexrelname | size
--------------+--------
docs_pkey | 672 kB
idx_bq | 10 MB
idx_full | 104 MB
10.4배 차이입니다. 벡터 자체는 32배 줄었는데 index는 10배 남짓입니다. 이 격차가 이 글에서 짚고 싶은 부분입니다.
32배와 10배 사이
차이의 이유는 HNSW index에 든 것이 벡터만이 아니라는 데 있습니다. HNSW는 계층 그래프입니다. 각 노드가 이웃으로 향하는 링크를 들고 있고, 그 개수를 m 파라미터가 정합니다. 위 실험에서는 m=16이었습니다.
링크는 양자화 대상이 아닙니다. 벡터를 96바이트로 줄여도 링크는 그대로입니다. 그래서 압축률이 벡터 크기 비율보다 낮게 나옵니다.
원문 수치로 확인해 봐도 같은 방향입니다. 367GB에서 38GB는 약 9.7배입니다. AWS가 “32배 압축"이라고 표현한 것은 벡터 데이터 자체의 비율이고, index 전체는 10배 안쪽입니다. 용량 계획을 세울 때 32배로 잡으면 어긋납니다.
원문이 준 벡터당 크기도 이 관점에서 읽힙니다. 1536차원에서 벡터당 약 680바이트, 768차원에서 약 400바이트입니다. 768비트는 96바이트니까 나머지 300바이트 정도가 그래프 구조입니다.
flowchart TD
A[float32 벡터
768차원 3072바이트] --> B[binary_quantize]
B --> C[bit 768
96바이트]
C --> D[HNSW 그래프 노드]
E[이웃 링크 m=16] --> D
D --> F[index 크기
= 벡터 + 링크]
재순위화가 없으면 반쪽이다
이진 양자화만으로 검색을 끝내면 정확도가 떨어집니다. 부호만 봤으니 당연합니다. 그래서 두 단계로 나눕니다. 양자화된 index로 후보를 넉넉히 뽑고, 그 후보들만 원본 벡터로 다시 정렬합니다.
원문이 제시한 쿼리 모양입니다.
SELECT * FROM (
SELECT id, embedding <=> '[query_vector]'::vector AS exact_distance
FROM your_table
ORDER BY binary_quantize(embedding)::bit(768) <~>
binary_quantize('[query_vector]'::vector)::bit(768)
LIMIT 200
) candidates
ORDER BY exact_distance
LIMIT 10;
연산자 두 개가 각각 다른 일을 합니다. <~>가 bit 타입의 Hamming 거리로 후보 200개를 고릅니다. <=>가 원본 vector의 코사인 거리로 그 200개를 다시 정렬합니다. 최종 10개는 원본 정밀도로 판단된 결과입니다.
이 구조에서 후보 개수가 정확도와 지연의 조절 손잡이입니다. 200개를 뽑으면 100개보다 정확하고 느립니다.
수치는 어디까지 좋아졌나
원문이 낸 측정치 중 눈에 띄는 것들입니다.
OpenAI 임베딩 500만 개(1536차원)를 r8g.large에서 돌린 결과입니다. 이진 양자화 HNSW가 recall 0.951에 138 QPS, p99 지연 18.9ms였습니다. 원본 정밀도 HNSW는 78 QPS에 p99 1,356ms였습니다. 지연 차이가 70배 넘게 벌어집니다.
LAION 1억 개(768차원)를 r8g.4xlarge에서 cold cache로 돌린 쪽이 더 극적입니다. 이진 양자화가 recall 0.931에 13.5 QPS, 원본 정밀도가 3.4 QPS입니다. 원문은 원본 정밀도 index가 메모리에 들어가지 않았다고 적었습니다. 이 한 줄이 사실 이 기법의 존재 이유입니다. 압축 자체가 목적이 아니라, index를 buffer cache 안에 들여놓는 것이 목적입니다.
index 빌드 시간도 1.1시간 대 16.1시간으로 갈렸습니다.
빌드 설정은 이렇게 잡았습니다.
maintenance_work_mem = 96GB
max_parallel_maintenance_workers = 48
쿼리 쪽 설정입니다.
SET hnsw.ef_search = 800;
SET hnsw.iterative_scan = relaxed_order;
SET hnsw.max_scan_tuples = 1400;
hnsw.iterative_scan이 여기서 역할이 있습니다. ef_search의 후보 한계인 1,000개를 넘겨 재순위화하려면 이 설정이 필요합니다.
요구 사항은 Aurora PostgreSQL 16.8 이상 또는 17.x이고 pgvector 0.8.0 이상입니다.
제 실측의 한계
위에서 크기는 재 봤지만 recall은 재지 않았습니다. 이유를 밝혀 두는 게 맞습니다.
제가 넣은 벡터는 random()-0.5로 만든 균등 난수입니다. 실제 임베딩과 분포가 다릅니다. 임베딩은 의미가 비슷한 것끼리 방향이 모이는 구조인데, 균등 난수는 모든 벡터가 서로 비슷하게 멀리 있습니다. 이런 데이터에서 recall을 재면 이진 양자화의 정보 손실이 실제와 다르게 나옵니다.
index 크기는 데이터 분포와 무관한 구조적 값이라 그대로 쓸 수 있고, 정확도는 실제 임베딩으로 재야 의미가 있습니다. 그 부분은 원문 수치를 인용하는 쪽이 정직합니다.
언제 쓸까
기준이 비교적 선명합니다. index가 메모리에 들어가느냐입니다.
들어가는 규모라면 이진 양자화의 이득이 작습니다. 원본 정밀도 HNSW가 이미 충분히 빠르고, 재순위화 단계가 붙지 않아 쿼리도 단순합니다.
들어가지 않는 규모라면 계산이 완전히 달라집니다. index를 디스크에서 읽는 순간 지연이 자리수 단위로 뛰기 때문에, recall을 0.95 근처로 유지하면서 index를 10분의 1로 줄이는 거래가 압도적으로 유리해집니다. 위 LAION 사례에서 QPS가 4배 차이 난 것이 그 지점입니다.
AlloyDB가 AI 에이전트에 문을 연 이야기를 다룰 때도 느낀 건데, 클라우드 3사가 벡터 쪽에서 경쟁하는 방향이 새 엔진이 아니라 PostgreSQL 위에 얹는 최적화로 모이고 있어요. 이번 것도 pgvector의 기존 기능을 조합한 결과입니다. binary_quantize와 bit_hamming_ops는 pgvector 0.8.0부터 있던 것이고, AWS가 한 일은 그것을 1억 벡터 규모에서 검증하고 설정값을 찾은 것입니다.
참고
- Scale pgvector with binary quantization on Amazon Aurora PostgreSQL (AWS Database Blog, 2026-08-18)
- pgvector 저장소