为什么规划者对具有不同波动率的函数提出不同的结果?

时间:2015-01-30 21:34:59

标签: postgresql function volatile sql-execution-plan

这个问题是SQL function very slow compared to query without function wrapper的后续和结果。我应该注意到,我不认为这是重复的,因为那个问题是要求解决特定问题。我要求提供有关此处一般行为的更多信息,并演示如何将其复制。 (为了证明这种差异,你可以在接受的答案中看到一个相当长的评论帖子,我们讨论了这个行为,我觉得它正在脱离主题,特别是考虑到篇幅。)

我有一个功能。这是展示感兴趣行为的样本:

CREATE OR REPLACE FUNCTION test(INT)
  RETURNS TABLE(num INT, letter TEXT)
  VOLATILE
  LANGUAGE SQL
  AS $$
  SELECT *
  FROM (VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')) x
  LIMIT $1
  $$;

当我运行此EXPLAIN时:

EXPLAIN ANALYZE SELECT * FROM test(10);

我在psql中得到了这个结果(我删除了一个巨大的“查询计划”标题):

 Function Scan on test  (cost=0.25..10.25 rows=1000 width=36) (actual time=0.125..0.136 rows=5 loops=1)
 Total runtime: 0.179 ms
(2 rows)

记下行估计。估计有1000行。

但是,如果我将功能更改为STABLEIMMUTABLE

CREATE OR REPLACE FUNCTION test(INT)
  RETURNS TABLE(num INT, letter TEXT)
  STABLE
  LANGUAGE SQL
  AS $$
  SELECT *
  FROM (VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')) x
  LIMIT $1
  $$;

然后同一个EXPLAIN给了我一个不同的计划:

 Limit  (cost=0.00..0.06 rows=5 width=36) (actual time=0.010..0.050 rows=5 loops=1)
   ->  Values Scan on "*VALUES*"  (cost=0.00..0.06 rows=5 width=36) (actual time=0.005..0.018 rows=5 loops=1)
 Total runtime: 0.087 ms
(3 rows)

现在它正确估计了5行,并显示了函数内包含的查询的计划。成本高出一个数量级。运行时也下降了。 (查询很短,可能不是特别重要。)

根据链接问题处理更多数据并且具有非常显着的性能差异,计划程序似乎实际上根据函数是VOLATILE还是STABLE执行了不同的操作/ IMMUTABLE

规划师到底做了什么,我在哪里可以阅读一些文件?

这些测试在PG 9.3中进行。

1 个答案:

答案 0 :(得分:2)

估计有1000行

1000估算的行是CREATE FUNCTION中记录的默认值:

  

<强> execution_cost

     

一个正数,给出函数的估计执行成本,单位为cpu_operator_cost。如果函数返回a   设置,这是每个返回行的成本。如果未指定成本,   假定C语言和内部函数为1个单位,100个单位   用于所有其他语言的功能。较大的值会导致计划者   试图避免不必要地评估函数。

     

<强> result_rows

     

给出计划员估计行数的正数   应该期望函数返回。这是唯一允许的   当声明函数返回一个集合时。默认假设   是1000行。

当函数声明为volatile时,它要求不内联,因此result_rows的默认值成立。

另一方面,当它在第二次测试中的查询中内联时,将估计行数,就好像函数体被移入查询和函数中一样声明不存在。这导致第二次测试得到精确估计,因为可以直接评估VALUES子句。

规划师到底做了什么,我在哪里可以阅读一些文档?

一般而言,主要文档中未说明规划人员的优化策略。他们在邮件列表中讨论并在源代码注释中提到,幸运的是,这些注释非常清晰且写得很好(与普通源代码相比)。在函数内联的情况下,我认为inline_set_returning_functionsinline_set_returning_function的注释揭示了推动此特定优化的大多数规则。 (警告:以上链接进入当前主分支,随时可能发生变化或漂移)。