PostgreSQL 教程: 调整函数的并行安全性

二月 19, 2024

摘要:在本教程中,您将学习如何调整函数的并行安全性。

介绍

规划器无法自动确定函数是否并行安全,但在某些情况下,如果处理大型数据集,并行模式可以显著提高性能。规划器会使用的工作进程数受参数 max_parallel_workers_per_gather 的限制,这些进程又来自由 max_worker_processes 指定建立的进程池,数目受参数 max_parallel_workers 限制,只要 max_worker_processes <= 服务器 CPU 核数,就可以通过以下公式确定以并行模式执行的最大并发查询数:

#Q_concurrent_par = max_worker_processes /max_parallel_workers_per_gather(整数除法)

什么时候对函数启用并行是安全的?

只要您的代码不执行以下操作,您就应该准备好启用并行:

  • 写入数据库。
  • 访问序列。
  • 更改事务状态。
  • 对参数设置进行持久化更改。
  • 访问临时表。
  • 使用游标。
  • 定义预备语句。

示例

让我们开始设置一个小的测试用例:

CREATE TABLE test1 (id integer, str text);

INSERT INTO test1 (id, str)
  SELECT i, 'xxx' FROM generate_series(1, 1000000) AS s(i);

创建了一个包含 1'000'000 行的简单表。此外,让我们再创建一个简单的函数:

CREATE OR REPLACE FUNCTION pair_div_4 (i int)
  RETURNS boolean AS $$
BEGIN
  IF i % 2 = 0 AND i % 4 = 0 THEN
    RETURN TRUE;
  END IF;
  RETURN FALSE;
END;
$$ LANGUAGE plpgsql;

当您在 WHERE 子句中调用这个函数时,优化器会做什么?

EXPLAIN ANALYZE SELECT * from test1 WHERE pair_div_4 (id);
                                                   QUERY PLAN
----------------------------------------------------------------------------------------------------------------
 Seq Scan on test1  (cost=0.00..262476.00 rows=333333 width=8) (actual time=0.207..787.020 rows=250000 loops=1)
   Filter: pair_div_4(id)
   Rows Removed by Filter: 750000
 Planning time: 0.100 ms
 Execution time: 792.776 ms
(5 rows)

要更改上面的函数的并行安全性,请执行以下操作:

ALTER FUNCTION pair_div_4(i int) PARALLEL SAFE;

规划器会检测到pair_div_4()是并行安全的,并以并行模式来运行查询。再来看一下执行计划:

EXPLAIN ANALYZE SELECT * from test1 WHERE pair_div_4 (id);
                                                          QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.00..189750.48 rows=333333 width=8) (actual time=0.502..511.806 rows=250000 loops=1)
   Workers Planned: 1
   Workers Launched: 1
   ->  Parallel Seq Scan on test1  (cost=0.00..155417.18 rows=196078 width=8) (actual time=0.283..451.079 rows=125000 loops=2)
         Filter: pair_div_4(id)
         Rows Removed by Filter: 375000
 Planning time: 2.412 ms
 Execution time: 517.604 ms
(8 rows)

如 explain 的输出所示,Workers Launched 标签的值为 1,这意味着此查询使用了 1 个工作进程 来执行,而前面的 EXPLAIN 是在没有并行的情况下执行的。

了解更多

PostgreSQL 优化