了解PostgreSQL中的执行计划和并行化

iyr7buue  于 2023-11-18  发布在  PostgreSQL
关注(0)|答案(1)|浏览(150)

我有一个表,在"char"[]类型的vector列中存储了1 M个384维向量。我试图通过使用并行化来加速以下查询:

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;

字符串
<#>pgvector扩展的点积运算符,vector是该扩展定义的类型,据我所知,它类似于real[]
我在AWS RDS的空闲层中运行此查询。Postgres示例有两个vCPU,因此我希望看到使用两个worker的改进。考虑到向量的高维性,我希望计算点积来支配执行时间,因此使用两个worker的性能几乎提高了2倍。
为了在没有并发的情况下运行,我这样做:

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)


接下来,我们强迫两个工人:

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)


主要问题是:为什么没有观察到预期的时间改进?然而,我真的很感激EXPLAIN ANALYZE的输出。特别是:

  • 显示的行数似乎并不反映表中的实际行数(即正好1 M)。
  • 我在哪里可以看到与点积计算相关的时间测量/估计?
  • 为什么在第二个输出中显示12行?(我认为应该是11行:1行用于标题,10行用于数据)
  • 最重要的是,EXPLAIN ANALYZE的输出揭示了没有获得预期时间改进的原因是什么?
2fjabf4q

2fjabf4q1#

你有一个基本的误解:并行工作者是在后端进程之外启动的,默认情况下后端进程也会做它的工作。所以如果你设置max_parallel_workers_per_gather = 1,你不会禁用并行查询,而是将其限制在一个额外的进程中。将参数设置为0将禁用并行查询。
有了这个,回答你的问题就更容易了:
1.如果有两个进程,每个进程读取500000行,如果有三个进程,每个进程读取333333行。
sort和gather节点的估计行数显示了PostgreSQL在没有LIMIT的情况下估计的行数,而实际的行数在它获取了足够的行以满足LIMIT时停止。在你知道之前,这种差异是令人惊讶的。然而,PostgreSQL仍然在其成本估计中考虑LIMIT
1.我假设“点积”是函数调用。如果你使用EXPLAIN (ANALYZE, VERBOSE),你可以看到它们:然后你在函数被求值的节点的输出列中看到函数调用。函数执行时间没有单独列出,而是包含在节点的执行时间中。
请注意,如果启用了track_functions,则可以从pg_stat_user_functions获取函数执行统计信息。
1.这12行是EXPLAIN的输出,而不是查询的输出。
1.你可以看到,并行顺序扫描的执行时间并没有因为第二个并行工作线程而变得更短。也许你的磁盘已经饱和。如果你想确定时间是花在CPU上还是做I/O,请启用track_io_timing

相关问题