Todos os produtos
Search
Central de documentação

ApsaraDB RDS:Use the pgvector extension to test performance based on HNSW indexes

Última atualização: Aug 20, 2026

Este tópico demonstra como avaliar o desempenho de busca vetorial no ApsaraDB RDS for PostgreSQL usando índices Hierarchical Navigable Small Worlds (HNSW). O teste utiliza a ferramenta ANN-Benchmarks para medir a taxa de recall, consultas por segundo (QPS) e tempo de criação do índice em diferentes combinações de parâmetros. Por padrão, o ANN-Benchmarks testa o desempenho single-threaded. Para testes de desempenho com concorrência, consulte Use the pgvector extension to test performance based on IVF indexes.

Ambiente de teste

Coloque a instância RDS e a instância Elastic Compute Service (ECS) na mesma Virtual Private Cloud (VPC) e vSwitch para evitar variações nos resultados causadas pela rede.

Componente

Especificação

Instância RDS

PostgreSQL 16, RDS High-availability Edition, pg.x8.2xlarge.2c (16 núcleos, 128 GB de memória), pgvector 0.8.0

Instância ECS

ecs.c6.xlarge (4 núcleos, 8 GiB de memória), Alibaba Cloud Linux 3

Ferramenta de teste

ANN-Benchmarks (single-threaded por padrão)

Pré-requisitos

Antes de começar, verifique se você possui:

  • Uma instância RDS for PostgreSQL com uma conta privilegiada chamada ann_testuser e um banco de dados chamado ann_testdb. Consulte Create a database and an account

  • A extensão pgvector (chamada vector no sistema) instalada em ann_testdb. Consulte Manage extensions

  • Docker instalado na instância ECS. Consulte Install Docker

Configure a instância ECS

Execute os comandos abaixo na instância ECS para baixar o ANN-Benchmarks e criar um ambiente Python:

# Download ANN-Benchmarks
cd ~
git clone https://github.com/erikbern/ann-benchmarks.git

# Install Conda and create the test environment
yum install git
yum install conda
conda create -n ann_test python=3.10.6
conda init bash
source /usr/etc/profile.d/conda.sh
conda activate ann_test

# Install dependencies
cd ~/ann-benchmarks/
pip install -r requirements.txt

Todas as etapas subsequentes são executadas dentro do ambiente virtual ann_test. Caso sua sessão expire devido a timeout, execute conda activate ann_test para reativar o ambiente.

Execute o benchmark

Etapa 1: Configure a conexão com o RDS

Adicione as configurações abaixo ao final do arquivo ~/ann-benchmarks/ann_benchmarks/algorithms/pgvector/module.py, substituindo os valores de exemplo pelos detalhes reais da sua conexão RDS:

# RDS instance connection settings
os.environ['ANN_BENCHMARKS_PG_USER'] = 'ann_testuser'
os.environ['ANN_BENCHMARKS_PG_PASSWORD'] = 'testPawword'       # Replace with your password
os.environ['ANN_BENCHMARKS_PG_DBNAME'] = 'ann_testdb'
os.environ['ANN_BENCHMARKS_PG_HOST'] = 'pgm-****.pg.rds.aliyuncs.com'  # Replace with your internal endpoint
os.environ['ANN_BENCHMARKS_PG_PORT'] = '5432'
os.environ['ANN_BENCHMARKS_PG_START_SERVICE'] = 'false'        # Disable automatic startup

Etapa 2: Configure os parâmetros de teste HNSW

Edite o arquivo ~/ann-benchmarks/ann_benchmarks/algorithms/pgvector/config.yml para definir as combinações de parâmetros a serem testadas. Este teste abrange três grupos: M-16(100), M-16(200) e M-24(200).

float:
  any:
  - base_args: ['@metric']
    constructor: PGVector
    disabled: false
    docker_tag: ann-benchmarks-pgvector
    module: ann_benchmarks.algorithms.pgvector
    name: pgvector
    run_groups:
      M-16(100):
        arg_groups: [{M: 16, efConstruction: 100}]
        args: {}
        query_args: [[10, 20, 40, 80, 120, 200, 400, 800]]
      M-16(200):
        arg_groups: [{M: 16, efConstruction: 200}]
        args: {}
        query_args: [[10, 20, 40, 80, 120, 200, 400, 800]]
      M-24(200):
        arg_groups: [{M: 24, efConstruction: 200}]
        args: {}
        query_args: [[10, 20, 40, 80, 120, 200, 400, 800]]

Descrição dos parâmetros:

Parâmetro

Descrição

M (em arg_groups)

Número máximo de nós vizinhos por nó em cada camada do grafo. Valores maiores geram um grafo mais denso, aumentando a taxa de recall e o tempo de criação do índice.

efConstruction (em arg_groups)

Tamanho do conjunto de candidatos durante a construção do índice. Valores maiores melhoram a taxa de recall, mas aumentam o tempo de criação.

ef_search (em query_args)

Tamanho do conjunto de candidatos durante as consultas. Valores maiores melhoram a taxa de recall e aumentam a latência da consulta.

Diretrizes de ajuste:

  • Para aumentar a taxa de recall: eleve M, efConstruction ou ef_search.

  • Para reduzir a latência da consulta: diminua ef_search.

  • Para diminuir o tempo de criação do índice: reduza efConstruction ou aumente o número de workers paralelos (consulte Apêndice: Impacto dos parâmetros no tempo de criação do índice).

  • Os valores padrão (M=16, ef_construction=64, ef_search=40) frequentemente resultam em recall subótimo. Ajuste esses valores conforme suas necessidades específicas.

Etapa 3: Crie a imagem Docker de teste

  1. (Opcional) Modifique o arquivo ~/ann-benchmarks/ann_benchmarks/algorithms/pgvector/Dockerfile para ignorar a configuração interna do PostgreSQL e usar apenas os pacotes psycopg e pgvector:

    FROM ann-benchmarks
    USER root
    RUN pip install psycopg[binary] pgvector
  2. Crie a imagem Docker:

    cd ~/ann-benchmarks/
    python install.py --algorithm pgvector

    Execute python install.py --help para visualizar todas as opções disponíveis.

Etapa 4: Baixe o conjunto de dados

Ao executar o script de teste, o ANN-Benchmarks baixa automaticamente o conjunto de dados especificado. Este teste utiliza o dataset nytimes-256-angular. Para detalhes sobre os datasets disponíveis, consulte Conjuntos de dados do ANN-Benchmarks.

Dataset

Dimensões

Linhas

Vetores de teste

Vizinhos mais próximos

Distância

NYTimes

256

290.000

10.000

100

Angular

Se os datasets públicos não corresponderem à sua carga de trabalho, converta seus dados vetoriais para o formato Hierarchical Data Format version 5 (HDF5) e utilize-os como um dataset personalizado. Consulte Custom datasets.

Etapa 5: Execute o teste e colete os resultados

  1. Execute o benchmark:

    Parâmetro

    Descrição

    --dataset

    Dataset a ser testado

    -k

    Valor LIMIT na consulta SQL — número de resultados a retornar

    --algorithm

    Algoritmo para benchmark (pgvector neste teste)

    --runs

    Número de execuções; o melhor conjunto de resultados é selecionado

    --parallelism

    Número de workers paralelos (padrão: 1)

    cd ~/ann-benchmarks
    nohup python run.py --dataset nytimes-256-angular -k 10 --algorithm pgvector --runs 1 > ann_benchmark_test.log 2>&1 &
    tail -f ann_benchmark_test.log
  2. Gere os gráficos de resultados:

    cd ~/ann-benchmarks
    python plot.py --dataset nytimes-256-angular --recompute
  3. (Opcional) Exporte resultados detalhados incluindo taxa de recall, QPS, tempo de resposta (RT), tempo de criação do índice e tamanho do índice:

    cd ~/ann-benchmarks
    python data_export.py --out res.csv

Resultados dos testes

Taxa de recall e QPS

A tabela a seguir apresenta os resultados obtidos com o dataset nytimes-256-angular. Todos os três grupos utilizam os mesmos valores de query_args (ef_search = 10, 20, 40, 80, 120, 200, 400, 800).

m ef_construction ef_search Taxa de recall QPS
16 100 10 0,630 1.423,985
20 0,741 1.131,941
40 0,820 836,017
80 0,871 574,733
120 0,894 440,076
200 0,918 297,267
400 0,945 162,759
800 0,969 84,268
16 200 10 0,683 1.299,667
20 0,781 1.094,968
40 0,849 790,838
80 0,895 533,826
120 0,914 405,975
200 0,933 272,591
400 0,956 148,688
800 0,977 76,555
24 200 10 0,767 1.182,747
20 0,840 922,770
40 0,887 639,899
80 0,920 411,140
120 0,936 303,323
200 0,953 199,752
400 0,973 105,506
800 0,988 53,904

Tempo de criação do índice

m

ef_construction

Tempo de criação (segundos)

16

100

33,35

16

200

57,66

24

200

87,23

Conclusões

O aumento de m, efConstruction e ef_search melhora consistentemente a taxa de recall, porém reduz o QPS e aumenta o tempo de criação. Especificamente:

  • Elevar ef_search aumenta a taxa de recall, mas reduz o QPS.

  • Elevar m e efConstruction aumenta a taxa de recall, reduz o QPS e prolonga o tempo de criação.

  • Se sua aplicação exige alto recall, evite os valores padrão dos parâmetros (m=16, ef_construction=64, ef_search=40), pois são otimizados para velocidade em vez de precisão.

Apêndice: Impacto dos parâmetros no tempo de criação do índice

Efeito de maintenance_work_mem

O parâmetro maintenance_work_mem define a memória máxima para operações de manutenção, como VACUUM e CREATE INDEX (unidade: KB). Aumentar esse valor reduz o tempo de criação, mas apenas até atingir o tamanho do dataset. Quando maintenance_work_mem excede o tamanho do dataset, o tempo de criação para de diminuir.

Os resultados abaixo foram obtidos com o tipo de instância pg.x8.2xlarge.2c (16 núcleos, 128 GB de memória), max_parallel_maintenance_workers=8 e o dataset nytimes-256-angular (~324 MB).

maintenance_work_mem

Tempo de criação (segundos)

64 MB (65.536 KB)

52,82

128 MB (131.072 KB)

46,79

256 MB (262.144 KB)

36,40

512 MB (524.288 KB)

18,90

1 GB (1.048.576 KB)

19,06

O tempo de criação estabiliza entre 512 MB e 1 GB porque ambos os valores excedem o tamanho do dataset de ~324 MB.

Efeito de max_parallel_maintenance_workers

O parâmetro max_parallel_maintenance_workers controla o número de workers paralelos para uma única operação CREATE INDEX. O tempo de criação diminui à medida que esse valor aumenta.

Os resultados abaixo utilizam o mesmo tipo de instância, maintenance_work_mem=2048 (2 GB) e o dataset nytimes-256-angular.

max_parallel_maintenance_workers

Tempo de criação (segundos)

1

76,00

2

51,34

4

32,49

8

19,66

12

14,44

16

13,07

24

13,15

Efeito das dimensões do vetor

Os resultados abaixo utilizam o dataset GloVe (1.183.514 linhas), m=16, efConstruction=64 e ef_search=40, com maintenance_work_mem=8 GB e max_parallel_maintenance_workers=16.

À medida que a dimensão do vetor aumenta, o tempo de criação do índice aumenta, a taxa de recall diminui, o QPS cai e a latência da consulta sobe.

Dimensão

Tempo de criação (segundos)

Taxa de recall

QPS

P99 (ms)

25

195,10

0,99985

192,94

7,84

50

236,92

0,99647

152,36

9,69

100

319,36

0,97231

126,89

11,14

200

529,33

0,93186

95,05

15,11

P99 representa a latência do percentil 99 — 99% de todas as requisições de consulta são concluídas dentro desse tempo.

Efeito do tamanho do dataset

Os resultados abaixo utilizam o dataset dbpedia-openai-{n}k-angular com m=48, efConstruction=256 e ef_search=200.

Conforme o número de linhas aumenta, o tempo de criação do índice cresce de forma não linear, a taxa de recall diminui, o QPS cai e a latência da consulta sobe.

Tamanho do dataset

Linhas (dezenas de milhar)

Tempo de criação (segundos)

Taxa de recall

QPS

P99 (ms)

100k

10

54,05

0,9993

171,74

8,93

200k

20

137,23

0,99901

146,78

10,81

500k

50

436,68

0,999

118,55

13,94

1.000k

100

957,26

0,99879

101,60

16,35

Datasets personalizados

Caso os datasets públicos não representem sua carga de trabalho, gere um dataset HDF5 personalizado a partir dos seus próprios dados vetoriais.

Este exemplo requer a extensão rds_ai. Para instalação, consulte Use the AI capabilities provided by the rds_ai extension .
  1. Execute o script abaixo para exportar seus dados vetoriais e os vizinhos ground-truth para um arquivo HDF5:

    import h5py
    import numpy as np
    import psycopg2
    import pgvector.psycopg2
    
    conn_info = {
        'host': 'pgm-****.rds.aliyuncs.com',
        'user': 'ann_testuser',
        'password': '****',
        'port': '5432',
        'dbname': 'ann_testdb'
    }
    
    embedding_len = 1024
    distance_top_n = 100
    query_batch_size = 100
    
    try:
        with psycopg2.connect(**conn_info) as connection:
            pgvector.psycopg2.register_vector(connection)
            with connection.cursor() as cur:
                # Fetch training vectors
                cur.execute("select count(1) from test_rag")
                count = cur.fetchone()[0]
    
                train_embeddings = []
                for start in range(0, count, query_batch_size):
                    query = f"SELECT embedding FROM test_rag ORDER BY id OFFSET {start} LIMIT {query_batch_size}"
                    cur.execute(query)
                    res = [embedding[0] for embedding in cur.fetchall()]
                    train_embeddings.extend(res)
                train = np.array(train_embeddings)
    
                # Generate query embeddings using rds_ai
                with open('query.txt', 'r', encoding='utf-8') as file:
                    queries = [query.strip() for query in file]
                test = []
                for query in queries:
                    cur.execute(f"SELECT rds_ai.embed('{query.strip()}')::vector(1024)")
                    test.extend([cur.fetchone()[0]])
                test = np.array(test)
    
        # Compute ground-truth nearest neighbors using angular distance
        dot_product = np.dot(test, train.T)
        norm_test = np.linalg.norm(test, axis=1, keepdims=True)
        norm_train = np.linalg.norm(train, axis=1, keepdims=True)
        similarity = dot_product / (norm_test * norm_train.T)
        distance_matrix = 1 - similarity
    
        neighbors = np.argsort(distance_matrix, axis=1)[:, :distance_top_n]
        distances = np.take_along_axis(distance_matrix, neighbors, axis=1)
    
        # Save to HDF5
        with h5py.File('custom_dataset.hdf5', 'w') as f:
            f.create_dataset('distances', data=distances)
            f.create_dataset('neighbors', data=neighbors)
            f.create_dataset('test', data=test)
            f.create_dataset('train', data=train)
            f.attrs.update({
                "type": "dense",
                "distance": "angular",
                "dimension": embedding_len,
                "point_type": "float"
            })
    
        print("The HDF5 file is created and the dataset is added.")
    
    except (Exception, psycopg2.DatabaseError) as error:
        print(f"Error: {error}")
  2. Registre o dataset personalizado na seção DATASETS do arquivo ~/ann-benchmarks/ann_benchmarks/datasets.py:

    DATASETS: Dict[str, Callable[[str], None]] = {
      ......,
      "<custom_dataset>": None,
    }
  3. Faça upload do arquivo custom_dataset.hdf5 para o diretório ~/ann-benchmarks e passe seu nome para o script run.py usando o parâmetro --dataset <custom_dataset>.

Próximos passos