4

我正在为 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的任何值生成一个固定计划。

在第二种情况下,优化器会根据指定的值生成一个计划,尽管不使用计划缓存,但它的效率要高得多。

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

4

2 回答 2

7

Tom Lane 在刚刚发布的 PostgreSQL 9.2中显着改善了这一点;请参阅PostgreSQL 9.2 中的新增功能

准备好的语句曾经被优化过一次,对参数的值没有任何了解。在 9.2 中,计划程序将使用与发送的参数有关的特定计划(查询将在执行时进行计划),除非查询被执行多次并且计划程序确定通用计划不会比特定计划贵太多.

这是一个长期存在且痛苦的问题,以前需要SET enable_...参数、使用包装函数 usingEXECUTE或其他丑陋的 hack。现在它应该“正常工作”。

升级。

对于其他阅读本文的人,您可以判断这个问题是否困扰您,因为auto_explain参数化/准备好的查询计划与您explain自己查询时获得的计划不同。要验证,PREPARE ... SELECT然后尝试EXPLAIN EXECUTE看看您是否有不同的计划EXPLAIN SELECT

另请参阅此先前的答案

于 2012-09-11T11:22:46.930 回答
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;
于 2012-09-11T11:31:51.350 回答