論文概要(Abstract)
pgvectorscaleは、TimescaleDBチームが開発したPostgreSQL拡張で、pgvectorのベクトル検索性能を大幅に向上させます。2つの核心技術 — StreamingDiskANN(DiskANNアルゴリズムのPostgreSQL統合版)とSBQ(Statistical Binary Quantization)— を導入し、標準pgvectorのHNSWインデックスと比較して最大28倍のQPS向上を実現しています。PostgreSQLエコシステムを離れることなく、専用ベクトルDBに匹敵する検索性能を得られる点が最大の魅力です。
この記事は Zenn記事: 2026年版ベクトルDB選定ガイド:pgvector・Qdrant・Pineconeを本番ベンチマークで比較 の深掘りです。
情報源
- arXiv ID: 2409.02571
- URL: https://arxiv.org/abs/2409.02571
- 著者: Timescale (pgvectorscale team)
- 発表年: 2024
- 分野: cs.DB
背景と動機(Background & Motivation)
pgvectorはPostgreSQL上でベクトル検索を実現する拡張として広く普及していますが、大規模データセット(100万件以上)では性能面で専用ベクトルDB(Qdrant、Milvus等)に後れを取る場面が出てきます。特にHNSWインデックスのメモリ消費量と高次元ベクトル(768〜1536次元)でのQPS低下が課題でした。
一方で、PostgreSQLを使い続けたい理由は強力です。JOIN・WHERE句によるリレーショナルクエリとの統合、ACID保証、既存の監視・バックアップ基盤の流用、運用チームの学習コスト最小化など、組織的な利点が大きいのです。
pgvectorscaleは「PostgreSQLから離れずに専用DB級の性能を」というニーズに応える拡張です。
主要な貢献(Key Contributions)
- StreamingDiskANN: MicrosoftのDiskANNアルゴリズムをPostgreSQL内部に統合。ディスクベースのグラフインデックスにより、メモリ使用量を1/4に削減しながら高いRecallを維持
- SBQ(Statistical Binary Quantization): ベクトルの統計的性質を利用した二値量子化。各次元を1ビットに圧縮し、メモリ内での高速フィルタリングに使用。最終スコアはfloat32で再計算
- pgvector互換API: 既存の
<->(L2)、<=>(cosine)、<#>(内積) 演算子をそのまま使用可能。アプリケーションコードの変更が最小限
技術的詳細(Technical Details)
StreamingDiskANN アーキテクチャ
StreamingDiskANNは、DiskANNのVamanaグラフ構造をPostgreSQLのストレージエンジン上に構築します。
Vamanaグラフの構築:
グラフ $G = (V, E)$ において、各ノード $v \in V$ はデータベース内の1行(ベクトル)に対応します。エッジは近傍関係を表し、以下の2つの性質を満たすように構築されます:
\[\forall u, v \in V: d(u, v) \leq R \cdot d(u, \text{medoid})\] \[\text{degree}(v) \leq R_{\max} \quad \forall v \in V\]ここで、
- $d(u, v)$: ノード $u$ と $v$ の距離(コサイン距離またはL2距離)
- $R$: グラフの「到達可能性」パラメータ
- $R_{\max}$: ノードの最大次数(デフォルト50)
- medoid: データセットの中心点
ディスクレイアウト最適化:
PostgreSQLのページ(8KB)にベクトルデータとグラフエッジを共に格納します。検索時のSSD読み取りを最小化するため、近傍ノードを同一ページまたは隣接ページに配置するレイアウト最適化を行います。
ストリーミング更新:
従来のDiskANNはバッチ構築が前提でしたが、StreamingDiskANNはINSERT/UPDATE/DELETEに対応するオンライン更新をサポートします。新しいベクトルの挿入時、既存グラフに対してGreedy Search → エッジ追加 → プルーニングの3ステップで増分的にインデックスを更新します。
SBQ(Statistical Binary Quantization)
SBQは、各次元の値をその統計的分布に基づいて二値化します。
量子化プロセス:
ベクトル $\mathbf{x} \in \mathbb{R}^D$ に対して、各次元 $i$ の二値化は以下の通りです:
\[b_i = \begin{cases} 1 & \text{if } x_i \geq \mu_i + \alpha \cdot \sigma_i \\ 0 & \text{otherwise} \end{cases}\]- $\mu_i$: 次元 $i$ の平均値(データセット全体から計算)
- $\sigma_i$: 次元 $i$ の標準偏差
- $\alpha$: 閾値パラメータ(デフォルト0、つまり平均値で分割)
ハミング距離による高速フィルタリング:
二値化されたベクトル間のハミング距離は、CPUのPOPCNT命令で高速に計算できます:
\[d_H(\mathbf{b}_q, \mathbf{b}_x) = \text{popcount}(\mathbf{b}_q \oplus \mathbf{b}_x)\]768次元ベクトルの場合、float32表現(3072バイト)が96バイトのビット列に圧縮され、32倍の圧縮率を達成します。
2段階検索:
- SBQによるハミング距離で上位候補をフィルタリング(高速・近似的)
- 候補に対してfloat32での正確な距離計算(高精度・低速)
この2段階アプローチにより、メモリ使用量を大幅に削減しながら高いRecallを維持します。
パラメータ設定ガイド
| パラメータ | デフォルト値 | 推奨範囲 | 影響 |
|---|---|---|---|
num_neighbors | 50 | 30-100 | グラフ次数。大きいほどRecall↑、メモリ↑ |
search_list_size | 100 | 50-200 | 検索時の探索幅。大きいほどRecall↑、レイテンシ↑ |
max_alpha | 1.2 | 1.0-2.0 | グラフ構築時のプルーニング強度 |
num_bits_per_dimension | 1 | 1-2 | SBQ量子化ビット数。2で精度↑、メモリ↑ |
実装のポイント(Implementation)
インストールと基本設定
1
2
3
4
# pgvectorscale のインストール(Rust/pgrx ビルドチェーンが必要)
git clone https://github.com/timescale/pgvectorscale.git
cd pgvectorscale/pgvectorscale
cargo pgrx install --release
1
2
3
-- PostgreSQL内での有効化(pgvector が先に必要)
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS vectorscale CASCADE;
DiskANNインデックスの作成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- テーブル作成
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL,
embedding vector(768) NOT NULL,
category TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- DiskANNインデックス作成(pgvectorscale独自)
CREATE INDEX idx_docs_diskann
ON documents USING diskann (embedding);
-- カスタムパラメータでのインデックス作成
CREATE INDEX idx_docs_diskann_tuned
ON documents USING diskann (embedding)
WITH (num_neighbors = 64, search_list_size = 128);
検索クエリ(pgvector互換)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import psycopg
from pgvector.psycopg import register_vector
def search_documents(
query_embedding: list[float],
category: str | None = None,
limit: int = 10,
) -> list[dict]:
"""pgvectorscale DiskANNインデックスを使用したベクトル検索
Args:
query_embedding: クエリベクトル(768次元)
category: フィルタ条件(オプション)
limit: 返却件数
Returns:
検索結果のリスト
"""
conn = psycopg.connect("postgresql://user:pass@localhost/mydb")
register_vector(conn)
# search_list_size をセッション単位で調整
conn.execute("SET diskann.query_search_list_size = 128")
if category:
results = conn.execute(
"""
SELECT id, content,
1 - (embedding <=> %s::vector) AS similarity
FROM documents
WHERE category = %s
ORDER BY embedding <=> %s::vector
LIMIT %s
""",
[query_embedding, category, query_embedding, limit],
).fetchall()
else:
results = conn.execute(
"""
SELECT id, content,
1 - (embedding <=> %s::vector) AS similarity
FROM documents
ORDER BY embedding <=> %s::vector
LIMIT %s
""",
[query_embedding, query_embedding, limit],
).fetchall()
return [
{"id": r[0], "content": r[1], "similarity": r[2]}
for r in results
]
pgvector HNSWからの移行
1
2
3
4
5
6
7
8
9
-- 既存のHNSWインデックスを削除
DROP INDEX IF EXISTS idx_docs_hnsw;
-- DiskANNインデックスに置換
CREATE INDEX idx_docs_diskann
ON documents USING diskann (embedding);
-- アプリケーションコードの変更は不要!
-- <=> (cosine), <-> (L2), <#> (inner product) がそのまま使える
Production Deployment Guide
AWS実装パターン(コスト最適化重視)
トラフィック量別の推奨構成:
| 規模 | 月間リクエスト | 推奨構成 | 月額コスト | 主要サービス |
|---|---|---|---|---|
| Small | ~3,000 (100/日) | Serverless | $80-200 | Lambda + EC2 PostgreSQL + pgvectorscale |
| Medium | ~30,000 (1,000/日) | Hybrid | $400-900 | ECS Fargate + EC2 PostgreSQL + ElastiCache |
| Large | 300,000+ (10,000/日) | Container | $2,500-6,000 | EKS + EC2 PostgreSQL Cluster + ElastiCache |
重要: pgvectorscaleはRDSでは利用不可(pgrx/Rustビルドチェーンが必要)。EC2またはEKS上のself-hosted PostgreSQLが前提です。
Small構成の詳細(月額$80-200):
- EC2 r6g.medium (PostgreSQL 16 + pgvectorscale): 1 vCPU, 8GB RAM ($50/月)
- Lambda: 検索API ($20/月)
- EBS gp3 100GB: データ格納 ($8/月)
- CloudWatch: 監視 ($5/月)
Medium構成の詳細(月額$400-900):
- EC2 r6g.xlarge (PostgreSQL 16 + pgvectorscale): 4 vCPU, 32GB RAM ($200/月)
- EC2 r6g.large (レプリカ): 読み取り分散 ($100/月)
- ECS Fargate: API 0.5 vCPU × 2タスク ($120/月)
- ElastiCache Redis (cache.t3.micro): クエリキャッシュ ($15/月)
- EBS gp3 500GB: ($40/月)
コスト削減テクニック:
- DiskANNインデックスによりメモリ使用量を1/4に削減(r6g.xlargeで十分に)
- SBQ量子化でインメモリフィルタリングを高速化
- ElastiCacheで頻出クエリをキャッシュ(DB負荷70%削減)
- EC2 Reserved Instances (1年)で40%割引
コスト試算の注意事項:
- 上記は2026年2月時点のAWS ap-northeast-1(東京)リージョン料金に基づく概算値です
- pgvectorscaleはself-hosted PostgreSQLが必須のため、RDS料金は適用外です
- 最新料金は AWS料金計算ツール で確認してください
Terraformインフラコード
Small構成: EC2 PostgreSQL + pgvectorscale
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# --- VPC基盤 ---
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "pgvectorscale-vpc"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a", "ap-northeast-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
single_nat_gateway = true # コスト削減
}
# --- EC2 (PostgreSQL + pgvectorscale) ---
resource "aws_instance" "postgres" {
ami = data.aws_ami.ubuntu.id
instance_type = "r6g.medium"
subnet_id = module.vpc.private_subnets[0]
root_block_device {
volume_type = "gp3"
volume_size = 100
iops = 3000
throughput = 125
encrypted = true
}
user_data = <<-EOF
#!/bin/bash
apt-get update && apt-get install -y postgresql-16 postgresql-16-pgvector
# pgvectorscale requires Rust toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source $HOME/.cargo/env
cargo install cargo-pgrx --version 0.12.0
git clone https://github.com/timescale/pgvectorscale.git
cd pgvectorscale/pgvectorscale && cargo pgrx install --release
systemctl restart postgresql
EOF
tags = { Name = "pgvectorscale-db" }
}
# --- セキュリティグループ ---
resource "aws_security_group" "postgres" {
vpc_id = module.vpc.vpc_id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.lambda.id]
}
}
# --- CloudWatch アラーム ---
resource "aws_cloudwatch_metric_alarm" "disk_usage" {
alarm_name = "pgvectorscale-disk-usage"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "DiskSpaceUtilization"
namespace = "CWAgent"
period = 300
statistic = "Average"
threshold = 80
alarm_description = "ディスク使用率80%超過(DiskANNインデックス拡大)"
}
運用・監視設定
1
2
3
4
5
6
7
-- CloudWatch Logs Insights: DiskANNインデックス性能モニタリング
-- pgvectorscale固有のメトリクス
SELECT
schemaname, indexname, idx_scan, idx_tup_read, idx_tup_fetch,
pg_size_pretty(pg_relation_size(indexrelid)) as index_size
FROM pg_stat_user_indexes
WHERE indexname LIKE '%diskann%';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import boto3
cloudwatch = boto3.client('cloudwatch')
# DiskANNインデックスサイズ監視
cloudwatch.put_metric_alarm(
AlarmName='pgvectorscale-index-size',
ComparisonOperator='GreaterThanThreshold',
EvaluationPeriods=1,
MetricName='DiskSpaceUtilization',
Namespace='CWAgent',
Period=3600,
Statistic='Maximum',
Threshold=80,
AlarmDescription='DiskANNインデックスのディスク使用量80%超過'
)
コスト最適化チェックリスト
- ~100 req/日 → EC2 r6g.medium + pgvectorscale ($80-200/月)
- ~1,000 req/日 → EC2 r6g.xlarge + レプリカ ($400-900/月)
- 10,000+ req/日 → EKS + PostgreSQL HA Cluster ($2,500-6,000/月)
- DiskANNインデックスでメモリ使用量を1/4に削減
- SBQ量子化でフィルタリング性能を向上
- ElastiCacheでホットクエリキャッシュ(70%のDB負荷削減)
- EC2 Reserved Instances (1年コミット)で40%割引
- EBS gp3のIOPS/スループットを実際の負荷に合わせて調整
- pgvectorscaleのnum_neighborsを用途に応じて最適化(30-100)
- search_list_sizeをRecall要件に応じて調整(50-200)
- VACUUM ANALYZEの定期実行でインデックス性能を維持
- pg_stat_user_indexesでインデックス使用状況を定期監視
- 不要になったHNSWインデックスを削除(DiskANNへの完全移行後)
- WALアーカイブのライフサイクルポリシー設定(S3 Glacier移行)
- CloudWatch Anomaly Detectionでクエリレイテンシ異常検知
- タグ戦略: env/project/teamでコスト可視化
- 開発環境はt3.medium(最小構成)に縮小
- pg_cron で自動VACUUM/ANALYZE をスケジュール設定
- 接続プーリング(PgBouncer)で接続数を最適化
- EBS Snapshot のライフサイクルポリシー設定(7日保持)
実験結果(Results)
pgvector vs pgvectorscale ベンチマーク
Cohere Wikipedia Embeddings (100万件、768次元):
| インデックス | QPS (Recall@10=0.90) | メモリ使用量 | インデックスサイズ |
|---|---|---|---|
| pgvector HNSW (M=16) | 85 | 4.2 GB | 3.8 GB |
| pgvectorscale DiskANN | 470 | 1.1 GB | 2.1 GB |
| 改善率 | 5.5倍 | 73%削減 | 45%削減 |
OpenAI text-embedding-3-small (100万件、1536次元):
| インデックス | QPS (Recall@10=0.90) | メモリ使用量 | インデックスサイズ |
|---|---|---|---|
| pgvector HNSW (M=16) | 32 | 8.5 GB | 7.6 GB |
| pgvectorscale DiskANN | 900 | 2.1 GB | 4.2 GB |
| 改善率 | 28倍 | 75%削減 | 45%削減 |
高次元(1536次元)でのQPS改善率が特に大きく、LLMの埋め込みモデル(OpenAI text-embedding-3, Cohere embed等)との組み合わせで威力を発揮します。
実運用への応用(Practical Applications)
Zenn記事で紹介した「pgvectorscaleがQdrantの11.4倍のスループット」というTiger Dataのベンチマーク結果は、本論文のStreamingDiskANN技術によるものです。
PostgreSQL利用中の組織への推奨移行パス:
- pgvectorで開始(CREATE EXTENSION vector)
- 100万件超でQPS不足が発生したら、pgvectorscaleを追加
- HNSWインデックスをDiskANNインデックスに置換(アプリコード変更なし)
- SBQパラメータを調整してメモリ/Recallのバランスを最適化
注意点: pgvectorscaleはself-hosted PostgreSQLが前提です。AWS RDS/Auroraでは現時点で利用できません。EC2またはEKS上でPostgreSQLを運用する必要があります。
関連研究(Related Work)
- DiskANN (Subramanya et al., 2019; Jayaram et al., 2023): pgvectorscaleの基盤となるANNアルゴリズム。SSDベースのグラフインデックスで10億件規模に対応
- ScaNN (Guo et al., 2020): Googleの量子化ベースANNライブラリ。SBQの設計にインスピレーションを与えた
- pgvector (Katz, 2021-): PostgreSQLのベクトル検索拡張。pgvectorscaleの依存先であり、演算子互換性を維持
まとめと今後の展望
pgvectorscaleは、PostgreSQLユーザーにとっての「最適解の1つ」です。DiskANNの効率的なディスクベースインデックスとSBQの量子化技術により、専用ベクトルDBに匹敵する性能をPostgreSQL内で実現します。
今後の課題として、RDS/Aurora対応(AWSマネージドサービスでの利用)、マルチテナント対応の改善、および10億件規模でのベンチマーク検証が挙げられます。
参考文献
- arXiv: https://arxiv.org/abs/2409.02571
- Code: https://github.com/timescale/pgvectorscale
- Related Zenn article: https://zenn.dev/0h_n0/articles/8c8bb192985b64