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

时间:2019-07-08 13:02:02

标签: 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

我对SQL优化非常陌生,并且试图了解以下行为:

目前isReportAdmin函数仅返回“ true”

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

运行报表查询时,大约需要两分钟的时间来执行。

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

需要两秒钟才能返回。

您能否用中间术语来解释,为什么函数调用会产生如此多的开销?在查询中是否存在处理此类功能的通用策略?

1 个答案:

答案 0 :(得分:3)

是的,PL / pgSQL确实产生了performance overhead。在大多数情况下,您可以通过将函数定义为language sql来消除开销:

create or replace function isreportadmin(employee_id integer) 
  RETURNS bool 
AS $$
  select true;
$$ 
LANGUAGE sql
stable;

如果将其定义为stable,Postgres通常可以使用inline(SQL)函数并完全摆脱开销。


您的实际函数很可能在数据库中进行了一些查找。您仍然可以将其保留为SQL函数。如果您例如有一个名为user_roles的表,您需要在其中查找所传递的employee_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;