PostgreSQL并行执行计划解读与向量查询性能不达预期排查
问题背景
我有一张存储100万条384维向量的表,其中vector列类型为char[]。尝试通过并行化加速使用pgvector扩展<#>点积算子的查询,测试SQL如下:
EXPLAIN ANALYZE WITH Vars(key) as ( VALUES (array_fill(1, ARRAY[384])::vector) ) SELECT content_id FROM MyTable, Vars ORDER BY vector::int[]::vector <#> key LIMIT 10;
key是全1的测试向量,vector为pgvector定义的类型(类似real[])。在AWS RDS免费版2vCPU实例上运行该查询,预期并行化后性能接近翻倍,但实际提升有限。
无并发设置及执行计划输出
设置语句:
set max_parallel_workers = 1; set max_parallel_workers_per_gather = 1; set enable_parallel_hash = off;
执行计划:
Limit (cost=94267.29..94268.44 rows=10 width=12) (actual time=15624.961..15634.530 rows=10 loops=1) -> Gather Merge (cost=94267.29..161913.85 rows=588231 width=12) (actual time=15624.958..15634.524 rows=10 loops=1) Workers Planned: 1 Workers Launched: 1 -> Sort (cost=93267.28..94737.86 rows=588231 width=12) (actual time=15607.302..15607.305 rows=7 loops=2) Sort Key: ((((mytable.vector)::integer[])::vector <#> '[1,1,...,1]'::vector)) Sort Method: top-N heapsort Memory: 25kB Worker 0: Sort Method: top-N heapsort Memory: 25kB -> Parallel Seq Scan on mytable (cost=0.00..80555.82 rows=588231 width=12) (actual time=0.413..15452.274 rows=500000 loops=2) Planning Time: 10.502 ms Execution Time: 15635.121 ms (11 rows)
强制2个并行worker的设置及执行计划输出
设置语句:
set force_parallel_mode = on; set max_parallel_workers = 2; set max_parallel_workers_per_gather = 2; set enable_parallel_hash = on;
执行计划:
Limit (cost=83268.20..83269.37 rows=10 width=12) (actual time=14369.219..14379.656 rows=10 loops=1) -> Gather Merge (cost=83268.20..180496.59 rows=833328 width=12) (actual time=14369.217..14379.647 rows=10 loops=1) Workers Planned: 2 Workers Launched: 2 -> Sort (cost=82268.18..83309.84 rows=416664 width=12) (actual time=14352.711..14352.714 rows=9 loops=3) Sort Key: ((((mytable.vector)::integer[])::vector <#> '[1,1,...,1]'::vector)) Sort Method: top-N heapsort Memory: 25kB Worker 0: Sort Method: top-N heapsort Memory: 25kB Worker 1: Sort Method: top-N heapsort Memory: 25kB -> Parallel Seq Scan on mytable (cost=0.00..73264.22 rows=416664 width=12) (actual time=0.611..14204.459 rows=333333 loops=3) Planning Time: 7.062 ms Execution Time: 14380.487 ms (12 rows)
疑问与解答
疑问1:执行计划中的行数值与表中实际100万行不符,原因是什么?
- 计划里的预估行数是基于表的统计信息计算的,可能统计信息过时,或者
char[]转vector的类型转换让优化器无法准确预估行数。 - 实际执行的行数是按worker拆分的总和:第一个计划里
Parallel Seq Scan的rows=500000 loops=2,50万×2正好是100万;第二个计划里rows=333333 loops=3,33.3万×3也接近100万,和实际表行数一致。
疑问2:在哪里可以查看点积计算相关的时间估算/实测值?
- 当前
EXPLAIN ANALYZE输出中,Parallel Seq Scan的实际时间(比如actual time=0.413..15452.274)就包含了点积计算的时间,因为点积是作为排序键在扫描过程中计算的。 - 若要更细分,可使用
EXPLAIN (ANALYZE, BUFFERS, TIMING),但PostgreSQL不会单独拆分算子耗时,只能通过总扫描时间减去纯扫描开销来估算点积耗时——从数据看,扫描的实际时间绝大部分都花在了类型转换和点积计算上。
疑问3:第二个执行计划输出为何显示12行?
- 执行计划的行数按节点层级统计:第二个计划启用了2个worker,每个worker的排序信息会单独占一行,比第一个计划多了
Worker 1: Sort Method: top-N heapsort Memory: 25kB这一行,所以总数从11行变成12行。
疑问4:执行计划揭示了哪些导致并行化性能未达预期的原因?
- 类型转换开销大:查询需要把
char[]转成int[]再转成vector才能计算点积,这是CPU密集型操作,2vCPU实例算力有限,无法完全发挥并行优势。 - Gather Merge开销:并行worker完成各自的top-N排序后,主进程需要做合并排序,额外的通信和同步开销抵消了部分并行收益。
- 硬件资源限制:AWS RDS免费版是2vCPU,启用2个worker后,主进程也要占用CPU资源,每个worker能分到的CPU时间不足,无法实现接近翻倍的性能提升。
- top-N排序开销:每个worker都要做一次top-N排序,主进程还要合并,这部分串行开销影响了整体并行效率。
内容的提问来源于stack exchange,提问作者AlwaysLearning
相关产品推荐
相关产品推荐

