PostgreSQL 原始查询与“函数返回表” - 性能上的巨大差异。为什么?

Evg*_*eny 6 postgresql performance query

我使用 PostgreSQL,它用于报告。目前的配置方式如下:

有一个复杂的查询返回报告数据,如下所示:

select Column1 as Name1, Column2 as Name2
from sometable tbl
inner join ...
where ...
and ...
and $1 <= somedate
and $2 >= somedate
group by ...
order by ...;
Run Code Online (Sandbox Code Playgroud)

有一个使用此查询的函数并定义为

CREATE OR REPLACE FUNCTION GetMyReport(IN fromdate timestamp without time zone, IN todate timestamp without time zone)
  RETURNS TABLE(Name1 character varying, Name2 character varying) AS
$BODY$

--query start
select Column1 as Name1, Column2 as Name2
from sometable tbl
inner join ...
where ...
and ...
and $1 <= somedate
and $2 >= somedate
group by ...
order by ...;
--query end

$BODY$
  LANGUAGE sql VOLATILE
  COST 10
  ROWS 1000;
Run Code Online (Sandbox Code Playgroud)

最后,当报告应用程序调用该函数时,它会发送以下 SQL:

select null::text as Name1, Name2 from GetMyReport ('2012-05-28T12:19:39.0000000+11:00'::timestamp, '2012-05-28T12:19:44.0000000+11:00'::timestamp);
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  • 当我只对数据库运行“查询”时,它运行得非常快。事实上,如果返回的数据相当小,在几秒钟内
  • 当我运行从报告应用程序传递的 sql 时,每次都需要疯狂的运行时间。实际上,查询返回的相同数据的时间超过 10 分钟。
  • 事实上,我可以运行原始查询,需要几毫秒,运行函数 - 需要大约 10 分钟,再次运行查询 - 毫秒,运行函数 - 再次运行 10 分钟,所有参数都完全相同。

那可能是什么原因?

Evg*_*eny 5

好的,这很容易。事实证明,数据库必须在知道参数之前准备查询计划,这会导致错误的结果。解决方案是使用 plpgsql 并返回 QUERY EXECUTE。现在性能与预期相同。

CREATE OR REPLACE FUNCTION GetMyReport(IN fromdate timestamp without time zone, IN todate timestamp without time zone)
  RETURNS TABLE(Name1 character varying, Name2 character varying) AS
$BODY$

BEGIN
RETURN QUERY EXECUTE'
select Column1 as Name1, Column2 as Name2
from sometable tbl
inner join ...
where ...
and ...
and $1 <= somedate
and $2 >= somedate
group by ...
order by ...;' USING $1, $2
END

$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 10
  ROWS 1000;
Run Code Online (Sandbox Code Playgroud)