【问题标题】:Why is the planner coming up with different results for functions with different volatilities?为什么规划器会针对具有不同波动率的函数得出不同的结果?
【发布时间】:2015-01-30 21:34:59
【问题描述】:

这个问题是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 中运行。

【问题讨论】:

    标签: postgresql function volatile sql-execution-plan


    【解决方案1】:

    估计有 1000 行

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

    执行成本

    一个正数,给出函数的估计执行成本,以 cpu_operator_cost 为单位。如果函数返回一个 设置,这是每个返回行的成本。如果没有指定费用, C 语言和内部函数假定 1 个单元,100 个单元 对于所有其他语言的函数。较大的值会导致规划器 尽量避免过于频繁地评估函数。

    result_rows

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

    当一个函数被声明为 volatile 时,它​​要求不被内联,所以 result_rows 的这个默认值成立。

    另一方面,当它在第二个测试中的查询中被内联时,行数将被估计为好像函数的主体已被移动到查询中并且函数声明没有存在。由于可以直接评估 VALUES 子句,因此这会在第二次测试中得到准确的估计。

    策划者究竟在做什么,我在哪里可以阅读有关它的一些文档?

    一般来说,规划器的优化策略不会在主文档中解释。它们在邮件列表中进行了讨论,并在源代码 cmets 中被提及,幸运的是,它们往往非常清晰且写得很好(与普通源代码相比)。在函数内联的情况下,我相信 inline_set_returning_functionsinline_set_returning_function 的 cmets 揭示了驱动这种特定优化的大部分规则。 (警告:以上链接指向当前主分支,随时可能发生变化或漂移)。

    【讨论】:

    • 你能指出任何关于内联函数的文档吗?我没能找到任何东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    相关资源
    最近更新 更多