pgvector용 PostgreSQL 튜닝

Completed

벡터 검색 워크로드는 기존 트랜잭션 또는 분석 쿼리에 비해 PostgreSQL에 다른 요구를 배치합니다. 이러한 차이점을 이해하면 구성 매개 변수를 튜닝하여 AI 애플리케이션에 대한 쿼리 대기 시간, 메모리 사용량 및 컴퓨팅 효율성을 최적화할 수 있습니다.

비고

이 단원의 코드 예제는 PostgreSQL 및 pgvector에 대한 구성 패턴을 보여 줍니다. 표시된 매개 변수 값은 튜닝을 위한 시작점입니다. 최적의 설정은 특정 워크로드, 데이터 세트 크기 및 하드웨어에 따라 달라집니다. 프로덕션 환경에 적용하기 전에 항상 테스트 환경의 변경 내용을 벤치마킹합니다.

Pgvector 컴퓨팅 및 메모리 요구 사항

벡터 유사성 검색에는 쿼리 벡터와 잠재적으로 수백만 개의 저장된 벡터 간의 컴퓨팅 거리가 포함됩니다. 이 계산 패턴은 인덱싱된 열을 기반으로 행을 필터링하거나 키 값에 테이블을 조인하는 기존 데이터베이스 작업과 근본적으로 다릅니다.

벡터 유사성 쿼리를 실행할 때 pgvector는 쿼리 벡터와 후보 벡터 사이의 거리를 계산해야 합니다. 1536차원 포함(OpenAI 모델에서 공통)의 경우 각 거리 계산에는 1,536개의 부동 소수점 작업이 포함됩니다. 인덱스 없이 백만 개의 벡터를 검색하려면 쿼리당 15억 개 이상의 부동 소수점 작업이 필요합니다. 세 거리 함수는 데이터 특성 및 성능 요구 사항에 따라 선택에 영향을 주는 계산 비용이 다릅니다.

  • L2(유클리드) 거리: 연산자를 <-> 사용하고 제곱 차이 합계의 제곱근을 계산합니다. 가장 계산 비용이 많이 드는 옵션입니다.
  • 코사인 거리: 연산자를 <=> 사용하고 벡터 사이의 각도를 측정합니다. 내부적으로 벡터를 정규화하여 계산량이 증가하지만, 스케일 불변 유사성을 제공합니다.
  • 내부 제품: 연산자를 <#> 사용하고 점 제품을 계산합니다. 가장 빠른 작업이지만 의미 있는 유사성 비교를 위해 미리 정규화된 벡터가 필요합니다.

권장 엔진 및 의미 체계 검색의 경우 코사인 거리는 다양한 크기의 벡터를 일관되게 처리하므로 선호되는 경우가 많습니다. embeddings가 이미 정규화된 경우(많은 포함 API가 정규화된 벡터를 반환함) 내부 제품은 더 적은 계산으로 동등한 결과를 제공합니다.

벡터 열은 기존 데이터 형식에 비해 상당한 스토리지를 사용합니다. 단일 정밀도로 float4 저장된 단일 1536차원 벡터에는 오버헤드를 더한 6,144바이트가 필요합니다. 100만 개의 제품 포함 테이블은 벡터 열에만 약 6GB가 필요합니다. PostgreSQL은 벡터 쿼리를 처리할 때 벡터 데이터를 메모리에 로드합니다. 사용 가능한 메모리와 벡터 데이터 크기 간의 관계는 쿼리가 메모리에서 효율적으로 실행되거나 디스크에서 반복적으로 읽어야 하는지에 직접적인 영향을 줍니다.

더 높은 차원 임베딩은 더 많은 의미 체계 해상도를 제공하지만 스토리지 및 계산 비용을 4차원적으로 증가합니다. 3072차원 벡터(일부 최신 포함 모델에서 사용됨)에는 거리 계산 작업의 4배, 1536차원 벡터 스토리지의 두 배가 필요합니다. 포함 차원을 선택할 때는 정확도 요구 사항을 고려해야 합니다. 많은 권장 사항 및 검색 애플리케이션의 경우 768 또는 1,024 차원은 의미 있는 리소스 사용량을 줄여 충분한 품질을 제공합니다.

벡터 워크로드에 대한 메모리 구성

PostgreSQL의 메모리 매개 변수는 벡터 쿼리 성능에 크게 영향을 줍니다. 적절한 튜닝을 통해 벡터 인덱스와 자주 액세스하는 데이터가 메모리에 유지되어 비용이 많이 드는 디스크 작업이 줄어듭니다.

매개 변수는 shared_buffers 자주 액세스하는 데이터 페이지가 있는 PostgreSQL의 공유 메모리 캐시를 제어합니다. 벡터 워크로드의 경우 이 캐시는 벡터 인덱스 및 핫 데이터를 저장할 수 있을 만큼 커야 합니다. 벡터가 많은 워크로드의% 99 미만의 캐시 적중 비율은 너무 작을 수 있음을 shared_buffers 나타냅니다. Azure Database for PostgreSQL에서 이 매개 변수는 컴퓨팅 계층에 따라 자동으로 조정되지만 계층에 허용되는 범위 내에서 조정할 수 있습니다. 전용 벡터 검색 워크로드의 경우 벡터 인덱스를 저장하고 캐시된 다른 데이터에 대해 충분한 여유 공간을 가질 수 있을 만큼 큰 shared_buffers를 목표로 하십시오. 시작점은 사용 가능한 메모리의 25%이며 모니터링에 따라 증가합니다. 다음 쿼리는 현재 설정 및 캐시 성능을 확인하는 데 도움이 됩니다.

-- Check current setting
SHOW shared_buffers;

-- View buffer cache hit ratio
SELECT
    sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS cache_hit_ratio
FROM pg_statio_user_tables;

매개 변수는 work_mem 정렬 및 해시 조인과 같은 개별 쿼리 작업에 사용할 수 있는 메모리를 제어합니다. 벡터 유사성 쿼리, 특히 벡터 검색과 필터링 및 순서를 결합하는 쿼리는 적절한 work_mem이점을 누릴 수 있습니다. 기본값 work_mem (일반적으로 4MB)은 유사성을 기준으로 결과를 정렬해야 하는 벡터 작업에 비해 너무 작은 경우가 많습니다. 를 사용하여 큰 결과 집합으로 벡터 검색을 수행하는 세션 또는 쿼리에 대해 이 값을 늘릴 수 있습니다 SET work_mem = '256MB';. 전역 설정 work_mem 값을 증가시킬 때 주의해야 합니다. 이 설정은 각 작업 및 연결마다 적용되므로, 복잡한 쿼리로 100개의 동시 연결을 처리하는 서버는 메모리에서 쿼리당 100 × work_mem × 작업 수에 해당하는 양을 사용할 수 있습니다. 벡터 워크로드의 경우 전역이 아닌 특정 쿼리에 대한 세션 수준에서 설정하는 work_mem 것이 좋습니다.

이 매개 변수는 effective_cache_size PostgreSQL shared_buffers 및 운영 체제의 파일 캐시를 포함하여 캐싱에 사용할 수 있는 메모리의 양을 쿼리 플래너에게 알려줍니다. 이 설정은 메모리를 할당하지 않지만 플래너가 순차적 검색을 통해 인덱스 검사를 선택하는지 여부에 영향을 줍니다. 전용 데이터베이스 서버의 총 시스템 메모리의 약 75%로 설정합니다 effective_cache_size . 값이 높을수록 플래너는 일반적으로 벡터 검색에 도움이 되는 인덱스를 사용하도록 권장합니다. Azure Database for PostgreSQL에서 계층에 따라 자동으로 구성됩니다.

PostgreSQL의 쿼리 플래너는 비용 예측에 따라 쿼리를 실행하는 방법을 결정합니다. 몇 가지 매개 변수는 이러한 예측에 영향을 줍니다. 최신 SSD 스토리지에 대해 튜닝하면 벡터 쿼리 계획이 향상됩니다.

매개 변수는 random_page_cost 순차적 페이지를 기준으로 임의 디스크 페이지를 읽는 비용을 예측합니다. 기본값 4.0은 임의 액세스가 순차적 액세스보다 훨씬 느린 회전 디스크 특성을 반영합니다. Azure Database for PostgreSQL은 임의 및 순차적 액세스의 성능이 비슷한 SSD 스토리지를 사용합니다. random_page_cost 1.1-1.5로 낮추면 플래너가 인덱스 검색을 더 쉽게 사용할 수 있으므로 분산된 데이터 페이지에 액세스하는 벡터 검색에 이점이 있습니다. 을 SET random_page_cost = 1.1;사용하여 이 설정을 조정할 수 있습니다.

이 매개 변수는 effective_io_concurrency PostgreSQL에 스토리지 시스템에서 처리할 수 있는 동시 디스크 I/O 작업의 수를 알려줍니다. 값이 높을수록 비트맵 힙 검색을 통해 더 많은 페이지를 병렬로 프리페치할 수 있습니다. SSD 스토리지는 동시 I/O 웰을 처리하므로 SSD 기반 Azure Database for PostgreSQL 인스턴스의 경우 200으로 설정합니다 effective_io_concurrency . 이렇게 하면 벡터 유사성과 메타데이터 필터링을 결합하는 쿼리의 성능이 향상됩니다.

PostgreSQL가 병렬 쿼리 실행을 사용할 시점을 parallel_tuple_cost 및 parallel_setup_cost 매개 변수가 제어합니다. 벡터 작업은 특히 큰 테이블의 순차적 검사에 대해 병렬 처리의 이점을 활용할 수 있습니다. (기본값 0.1) 및 parallel_tuple_cost (기본값 1000)에 대한 parallel_setup_cost 값이 낮을 경우 병렬 실행이 권장됩니다. 테이블이 큰 벡터 워크로드의 경우 병렬 처리를 사용하면 인덱스를 사용하지 않을 때 쿼리 시간이 크게 단축될 수 있습니다. SHOW parallel_tuple_cost;, SHOW parallel_setup_cost;, 및 SHOW max_parallel_workers_per_gather;를 사용하여 현재 병렬 설정을 확인할 수 있습니다.

pgvector 관련 매개 변수 구성

pgvector 확장은 인덱스 기반 검색에 대한 정확도-속도 절차를 제어하는 구성 매개 변수를 제공합니다. 이러한 매개 변수는 벡터 쿼리 성능을 조정하는 데 중요합니다.

IVFFlat 인덱스를 사용하는 경우 매개 변수는 ivfflat.probes 각 쿼리에 대해 검색되는 인덱스 파티션(목록)의 수를 제어합니다. 값이 높을수록 회수가 증가하지만(가장 가까운 실제 인접 항목을 더 많이 찾습니다) 쿼리는 느립니다. 이 절충이 IVFFlat 성능 튜닝의 핵심입니다. 더 많은 파티션을 검색하는 비용과 좋은 매치를 놓칠 위험을 균형 잡고 있습니다. 기본값 1 은 가장 유망한 단일 파티션만 검색합니다. 이 파티션은 빠르지만 인접 파티션에 저장된 관련 결과를 놓칠 수 있습니다. 추천 엔진에서 적합한 일치를 놓치면 사용자 경험이 저하되는 경우, 먼저 ivfflat.probes를 lists 매개 변수의 5~10%로 설정하고 측정된 재현율에 따라 조정합니다.

-- Configure IVFFlat search depth
SET ivfflat.probes = 10;

-- Execute vector search
SELECT id, name, embedding <=> $1 AS distance
FROM products
ORDER BY embedding <=> $1
LIMIT 10;

HNSW 인덱스의 경우 매개 변수는 hnsw.ef_search 검색하는 동안 동적 후보 목록의 크기를 제어합니다. 값이 클수록 그래프를 더 많이 탐색하여 회수가 향상되지만, 그 대가로 속도가 감소합니다. IVFFlat의 개별 파티션과 달리 HNSW의 그래프 구조는 이 매개 변수가 결과를 반환하기 전에 알고리즘이 인접 연결을 탐색하는 방법에 영향을 줍니다. 기본값 40은 많은 워크로드에 적절한 균형을 제공합니다. 정확도가 높은 요구 사항(예: 실제 상위 10개 일치 항목 찾기)의 경우 100-200으로 증가합니다. 대략적인 결과가 허용되는 대기 시간 중요 애플리케이션의 경우 20의 낮은 값이 작동할 수 있습니다. 벡터 검색을 실행하기 전에 hnsw.ef_search를 SET hnsw.ef_search = 100;로 구성합니다. 최적 값은 정확도 요구 사항 및 대기 시간 예산에 따라 달라집니다. 대표적인 쿼리를 벤치마킹하여 애플리케이션에 적합한 균형을 찾습니다.

성능 모니터링 및 측정

측정하지 않고 튜닝하는 것은 추측입니다. PostgreSQL의 기본 제공 도구 및 Azure Monitor를 사용하여 쿼리 동작을 이해하고 구성 변경 내용의 유효성을 검사합니다.

이 EXPLAIN ANALYZE 명령은 PostgreSQL이 쿼리를 실행하고 실제 타이밍 정보를 제공하는 방법을 보여 줍니다. 벡터 쿼리의 경우 인덱스가 사용되는지 여부와 시간이 소요되는 위치를 알 수 있습니다. 실행 계획을 이해하면 성능 저하가 누락된 인덱스, 최적이 아닌 매개 변수 설정 또는 데이터 배포 문제에서 비롯되는지 여부를 식별할 수 있습니다. 벡터 쿼리 전에 실행 EXPLAIN ANALYZE 하여 실행 계획을 확인합니다. Index Scan using [index_name](벡터 인덱스가 사용 중임을 나타낸다), Seq Scan(큰 테이블에 대해 느린 순차 검사 표시), 실제 시간 값(실행 시간이 어디에 소요되고 있는지 표시) 및 행 개수(필터링이 효율적으로 작동하는지 식별하는 데 도움이 됨)를 찾습니다. 인덱스를 사용해야 할 때 순차 검색이 표시되는 경우 쿼리의 거리 연산자가 인덱스의 연산자 클래스와 일치하는지 확인합니다(예를 들어, <=>와 함께 vector_cosine_ops로 생성된 인덱스를 사용하는 경우).

경우에 따라 PostgreSQL은 사용 가능한 인덱스를 사용하지 않도록 선택합니다. 벡터 쿼리의 일반적인 원인으로는 테이블의 상당 부분을 반환하는 쿼리(인덱스 오버헤드가 순차적 검색을 초과함), 중요한 데이터 변경 후 오래된 통계 또는 인덱스의 연산자 클래스와 일치하지 않는 거리 연산자가 있습니다. 정확한 계획에 대한 통계를 업데이트하려면 실행 ANALYZE products; 합니다. 를 사용하여 인덱스 SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'products';정보를 확인할 수 있습니다.

Azure Database for PostgreSQL은 성능 병목 상태를 식별하는 데 도움이 되는 Azure Monitor를 통해 메트릭을 노출합니다. CPU 백분율(높은 지속형 CPU는 컴퓨팅 바인딩된 벡터 작업을 나타낸다), 메모리 비율(제한에 접근하면 컴퓨팅 계층 증가 또는 쿼리 최적화 제안), 스토리지 IO 백분율(높은 값은 데이터가 캐시에 적합하지 않음을 나타낸다), 활성 연결(제한에 접근하면 연결 풀링이 도움이 될 수 있음). 사용자에게 영향을 미치기 전에 성능 저하를 catch하도록 이러한 메트릭에 대한 경고를 설정합니다.

pgvector 튜닝 모범 사례

효과적인 튜닝은 임의 매개 변수 변경이 아닌 체계적인 접근 방식을 따릅니다.

  • 먼저 기준을 설정합니다. 변경하기 전에 쿼리 대기 시간 및 리소스 사용량을 측정합니다. 기준이 없으면 변경 내용이 도움이 되는지 여부를 확인할 수 없습니다.
  • 한 번에 하나의 매개 변수를 변경합니다. 여러 개의 동시 변경으로 특정 설정에 대한 개선 또는 회귀 특성을 지정할 수 없습니다.
  • 프로덕션과 유사한 데이터로 테스트: 쿼리 성능은 데이터 크기 및 배포에 따라 크게 달라집니다. 작은 테스트 데이터 세트를 튜닝하면 대규모로 실패하는 설정이 생성되는 경우가 많습니다.
  • 회귀 모니터링: 벡터 검색을 개선하는 매개 변수는 다른 워크로드에 부정적인 영향을 줄 수 있습니다. 변경 후 전체 시스템 상태를 모니터링합니다.
  • 설정을 문서화합니다. 변경한 내용, 이유 및 영향을 기록합니다. 이 설명서는 향후 문제를 해결할 때 매우 중요합니다.

추가 리소스