Ste*_*orn 3 postgresql postgresql-9.1
我有一个非常简单的查询,它并不复杂:
select *
from table_name
where id = 1234
Run Code Online (Sandbox Code Playgroud)
...运行时间不到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;
Run Code Online (Sandbox Code Playgroud)
执行此功能select * from pie(123);
需要22秒.
如果我硬编码整数代替id_param,则该函数在50毫秒内执行.
为什么我在where语句中使用参数会导致我的函数运行缓慢?
编辑以添加具体示例:
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
Run Code Online (Sandbox Code Playgroud)
即使使用预准备语句,也允许计划程序为特定参数值生成自定义计划(Tom Lane)
过去,准备好的语句总是有一个用于所有参数值的"通用"计划,这通常远远低于用于包含显式常量值的非预处理语句的计划.现在,计划程序尝试为特定参数值生成自定义计划.只有在反复证明自定义计划不能提供任何好处之后,才能使用通用计划.此更改应消除以前使用预准备语句(包括PL/pgSQL中的非动态语句)所看到的性能损失.
plpgsql函数具有与PREPARE
语句类似的效果:解析查询并缓存查询计划.
优点是每次调用都会节省一些开销.
缺点是查询计划没有针对调用它的特定参数值进行优化.
对于具有偶数数据分布的表的查询,这通常没有问题,并且PL/pgSQL函数的执行速度比原始SQL查询或SQL函数快一些.但是,如果您的查询可以根据WHERE
子句中的实际值使用某些索引,或者更一般地,为特定值选择更好的查询计划,则最终可能会得到次优查询计划.尝试使用SQL函数或使用动态SQL EXECUTE
强制为每个调用重新计划查询.看起来像这样:
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;
Run Code Online (Sandbox Code Playgroud)
评论后编辑:
如果此变体不会改变执行时间,则必须有其他因素可能已经错过或未提及.不同数据库?不同的参数值?你必须发布更多细节.
我在手册中添加了一个引用来支持我的上述陈述:
具有简单常量命令字符串和一些USING参数的EXECUTE(如上面的第一个示例)在功能上等同于直接在PL/pgSQL中编写命令并允许自动替换PL/pgSQL变量.重要的区别是EXECUTE将在每次执行时重新规划命令,生成特定于当前参数值的计划; 而PL/pgSQL通常会创建一个通用计划并将其缓存以供重用.在最佳计划强烈依赖于参数值的情况下,EXECUTE可以明显更快; 当计划对参数值不敏感时,重新规划将是一种浪费.
归档时间: |
|
查看次数: |
2945 次 |
最近记录: |