我有一个非常简单的查询,它比以下内容要复杂得多:

select *
from table_name
where id = 1234

...运行不到50毫秒。

采用该查询并将其纳入功能:

CREATE OR REPLACE FUNCTION pie(id_param integer)
RETURNS SETOF record AS
$BODY$
BEGIN
    RETURN QUERY SELECT *
         FROM table_name
         where id = id_param;
END
$BODY$
LANGUAGE plpgsql STABLE;

执行此功能 select * from pie(123); 需要22秒。

如果我硬编码整数代替ID_PARAM,则该函数将在50毫秒以下执行。

为什么我在语句中使用参数导致我的函数运行慢的事实?


编辑以添加具体示例:

CREATE TYPE test_type AS (gid integer, geocode character varying(9))

CREATE OR REPLACE FUNCTION geocode_route_by_geocode(geocode_param character)
  RETURNS SETOF test_type AS
$BODY$
BEGIN
RETURN QUERY EXECUTE
    'SELECT     gs.geo_shape_id AS gid,     
        gs.geocode
    FROM geo_shapes gs
    WHERE geocode = $1
    AND geo_type = 1 
    GROUP BY geography, gid, geocode' USING geocode_param;
END;

$BODY$
  LANGUAGE plpgsql STABLE;
ALTER FUNCTION geocode_carrier_route_by_geocode(character)
  OWNER TO root;

--Runs in 20 seconds
select * from geocode_route_by_geocode('999xyz');

--Runs in 10 milliseconds
SELECT  gs.geo_shape_id AS gid,     
        gs.geocode
    FROM geo_shapes gs
    WHERE geocode = '9999xyz'
    AND geo_type = 1 
    GROUP BY geography, gid, geocode
有帮助吗?

解决方案

更新PostgreSQL 9.2

有一个重大改进,我引用了 发行说明在这里:

即使使用准备好的语句(Tom Lane),允许计划者即使使用预定的参数值生成自定义计划

过去,准备好的语句始终具有用于所有参数值的单个“通用”计划,该计划通常远低于包含明确常数值的非准备陈述的计划。现在,计划者试图为特定参数值生成自定义计划。只有在自定义计划反复证明没有提供任何好处之后,才会使用通用计划。这种变化应消除以前从使用准备的陈述(包括PL/PGSQL中的非动态陈述)中看到的绩效惩罚。


PostgreSQL 9.1或以上的原始答案

PLPGSQL函数的作用与 PREPARE 声明:查询是解析的,查询计划被缓存。

优势是为每个呼叫保存一些开销。
缺点是查询计划未针对所调用的特定参数值进行优化。

对于具有偶数数据分布的表上的查询,这通常不会出现问题,并且PL/PGSQL功能的执行速度将比RAW SQL查询或SQL函数快一些。但是,如果您的查询可以根据实际值使用某些索引 WHERE 条款或更一般而言,为特定值选择一个更好的查询计划,您可能会得到一个优化的查询计划。尝试SQL功能或使用动态SQL EXECUTE 迫使A查询要重新计划每个呼叫。看起来像这样:

CREATE OR REPLACE FUNCTION pie(id_param integer)
RETURNS SETOF record AS
$BODY$
BEGIN        
    RETURN QUERY EXECUTE
        'SELECT *
         FROM   table_name
         where  id = $1'
    USING id_param;
END
$BODY$
LANGUAGE plpgsql STABLE;

评论后编辑:

如果此变体没有改变执行时间,则必须有其他因素在玩,您可能会错过或没有提及。不同的数据库?不同的参数值?您必须发布更多详细信息。

我添加报价 来自手册 备份我的上述陈述:

具有简单常数命令字符串和一些使用参数的执行(如上一个示例中)在功能上等效于仅在PL/PGSQL中直接编写命令,并允许更换PL/PGSQL变量自动发生。重要的区别在于,执行将在每个执行上重新计划命令,从而生成特定于当前参数值的计划;而PL/PGSQL通常会创建一个通用计划并缓存以重复使用。在最佳计划在很大程度上取决于参数值的情况下,执行的速度可以更快。当计划对参数值不敏感时,重新计划将是浪费。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top