SQL 函数的 PARALLEL SAFE 与并行查询兼容声明规范

6次阅读

SQL 函数的 PARALLEL SAFE 与并行查询兼容声明规范

postgresql 中的 PARALLEL SAFE 是一个函数属性声明,用于明确告知查询规划器:该函数在并行执行上下文中是安全的,可以被下推到并行工作进程(worker)中执行。它不是“开启并行”的开关,而是“允许并行”的前提条件之一。

PARALLEL SAFE 的作用与意义

当 PostgreSQL 启动并行查询(如并行顺序扫描、并行聚合等)时,规划器会检查涉及的函数是否标记为 PARALLEL SAFE。若函数未声明或声明为 PARALLEL RESTRICTED / PARALLEL UNSAFE,则整个并行计划可能被降级为串行执行,或相关计算被迫保留在主进程(leader)中完成,削弱并行收益。

注意:PARALLEL SAFE 不代表函数一定会被并行调用,它只是移除了并行执行的障碍;是否真正并行,还取决于查询结构、成本估算、max_parallel_workers_per_gather 设置及系统资源等。

三种并行兼容性级别对比

PostgreSQL 定义了三个函数并行安全性级别,必须显式指定(默认为 PARALLEL RESTRICTED):

  • PARALLEL SAFE:函数不访问共享状态(如序列、临时表、客户端连接信息)、不修改数据库、不依赖会话级变量(如 current_usersession_user)、不调用非 SAFE 函数。可安全地在任意 worker 进程中多次执行。
  • PARALLEL RESTRICTED:函数可在 leader 进程中执行,但不能下推至 worker(例如依赖 pg_backend_pid()clock_timestamp() 或写入临时表)。这是用户自定义函数的默认级别。
  • PARALLEL UNSAFE:函数存在明显副作用或状态依赖(如修改全局变量、调用 dblink、执行 DML),禁止在并行上下文中调用,否则可能导致错误或数据不一致。

如何正确声明 PARALLEL SAFE

在创建函数时,通过 PARALLEL 子句显式指定:

CREATE OR REPLACE function my_add(a int, b int)
  RETURNS int AS $$ select a + b; $$
  LANGUAGE SQL
  PARALLEL SAFE;

关键注意事项:

  • 所有被该函数直接或间接调用的其他函数,也必须是 PARALLEL SAFE,否则声明无效,建表时会报错。
  • 函数体中不可出现:NEXTVAL/CURRVAL(序列)、txid_current()pg_snapshot_xmin()set_config()、对临时表的读写、PL/pgSQL 的 GET DIAGNOSTICS 等。
  • 纯计算类函数(如字符串处理、数学运算、json 解析)通常天然适合标记为 PARALLEL SAFE;含 I/O、状态变更、事务/会话依赖的操作需谨慎评估。

验证与调试技巧

可通过系统视图确认函数的并行属性:

SELECT proname, proparallel
  FROM pg_proc
  WHERE proname = ‘my_add’;

返回值含义:s=SAFE,r=RESTRICTED,u=UNSAFE。

启用并行查询后,使用 EXPLAIN (ANALYZE, VERBOSE) 查看执行计划,观察函数调用是否出现在 Gather 节点之下(即由 worker 执行),是判断其是否真正并行化的直接依据。

text=ZqhQzanResources