如何使PostgresQL优化器在绑定参数后构建执行计划?

时间:2012-09-11 11:09:07

标签: sql postgresql sql-optimization

我正在为PostgresQL 9.1开发Pg / PLSQL函数。当我在SQL查询中使用变量时,优化器会构建错误的执行计划。但是,如果我用它的值替换变量,那么计划就可以了。 例如:

v_param := 100;
select count(*)
  into result
  from <some tables>
 where <some conditions>
       and id = v_param

在3s内完成

select count(*)
  into result
  from <some tables>
 where <some conditions>
       and id = 100

在300毫秒内完成

在第一种情况下,优化程序会为 v_param 的任何值生成固定计划。

在第二种情况下,优化器根据指定的值生成计划,尽管不使用计划缓存,但它的效率明显提高。

是否可以让优化器在没有动态绑定的情况下生成计划,并在每次执行查询时生成计划?

2 个答案:

答案 0 :(得分:6)

Tom Lane在just-released PostgreSQL 9.2中已经大大改善了这一点;特别参见What's new in PostgreSQL 9.2

  

准备好的语句曾经被优化过一次,没有任何知识   参数的值。使用9.2,规划人员将使用具体的   关于发送的参数的计划(查询将计划在   执行),除非查询执行了几次而且   计划者决定通用计划不会太昂贵   而不是具体的计划。

这是一个长期而痛苦的疣,以前需要SET enable_...参数,使用EXECUTE或其他丑陋黑客的包装函数。现在它应该“正常工作”。

升级。

对于阅读此内容的其他人,您可以判断此问题是否正在咬你,因为参数化/准备好的查询的auto_explain计划将与您自己explain查询时获得的计划不同。要进行验证,请尝试PREPARE ... SELECT然后EXPLAIN EXECUTE,看看您是否获得了与EXPLAIN SELECT不同的计划。

另见this prior answer

答案 1 :(得分:3)

动态查询不使用缓存计划 - 因此您可以使用9.1及更早版本中的EXECUTE USING语句。如克雷格写的那样,9.2应该没有这种解决方法。

v_param := 100;
EXECUTE 'select count(*) into result from <some tables> where <some conditions>
   and id = $1' USING v_param;