plpgsql 函数会产生巨大的性能开销

Bla*_*ack 3 sql postgresql

我在数据库后端使用 Postgres 9.3 的报告中有以下相当简单的查询:

SELECT * FROM source
JOIN sourcelevel USING (source_id)
JOIN level USING (level_id)
WHERE
  CASE WHEN isReportAdmin(1) THEN true
  ELSE source_id in (SELECT source_id FROM sourceemployee WHERE employee = 1)
  END
Run Code Online (Sandbox Code Playgroud)

我对 SQL 优化很陌生,我试图了解以下行为:

目前该isReportAdmin函数仅返回“true”

create or replace function isReportAdmin(employee_id integer) RETURNS bool AS $$
        BEGIN
                RETURN 't';
        END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

当我运行报告查询时,大约需要两分钟来执行。

如果我简单地替换函数调用: CASE WHEN true THEN...

返回需要两秒钟。

你能解释一下,为什么函数调用会产生如此多的开销?在查询中处理此类函数是否有通用策略?

a_h*_*ame 9

是的,PL/pgSQL 确实会产生性能开销。在大多数情况下,您可以通过将函数定义为language sql

create or replace function isreportadmin(employee_id integer) 
  RETURNS bool 
AS $$
  select true;
$$ 
LANGUAGE sql
stable;
Run Code Online (Sandbox Code Playgroud)

如果它被定义为stablePostgres 通常能够内联(SQL)函数并完全摆脱开销。


很可能您的实际函数在数据库中进行了一些查找。您仍然可以将其保留为 SQL 函数。例如,如果您有一个名为的表user_roles,您需要在其中查找传递的员工 ID,则可以使用以下内容:

create or replace function isreportadmin(p_employee_id integer) 
  RETURNS bool 
AS $$
  select exists (select *
                 from user_roles ur
                 where ur.employee_id = p_employee_id 
                   and ur.is_admin);
$$ 
LANGUAGE sql
stable;
Run Code Online (Sandbox Code Playgroud)