Postgres会执行视图中未选择的计算列的计算吗?


8

我试图了解从视图中选择数据的性能影响,其中视图中的列之一是原始表中其他数据的功能。

不管计算的列是否在所选列的列表中,都可以执行计算吗?

如果我有一个表并且视图这样声明

CREATE TABLE price_data (
    ticker     text,          -- Ticker of the stock
    ddate      date,          -- Date for this price
    price      float8,        -- Closing price on this date
    factor     float8         -- Factor to convert this price to USD
);

CREATE VIEW prices AS 
    SELECT ticker, 
           ddate,
           price,
           factor,
           price * factor as price_usd
    FROM price_data

乘法类似下面的查询来执行?

select ticker, ddate, price, factor from prices

是否有参考文献可以保证这种方式?我正在阅读Postgres中规则系统的文档,但是我认为答案确实在于优化器,因为规则系统文档中没有任何内容表明不会选择它。

我怀疑在上述情况下未执行计算。我改变视图,以使用除法来代替乘法,并插入一个0用于factor进入price_data。上面的查询没有失败,但是如果查询被修改为选择计算列,则修改后的查询将失败。

当执行a时,有什么方法可以理解正在select执行什么计算?我想我正在寻找类似的东西,EXPLAIN但它也告诉我正在执行的计算。


1
这是我们要鼓励在该SE上提出的一个很好的问题
Gaius

Answers:


6

就像@Laurenz所说的那样,您的分析是正确的:优化程序将避免评估不影响查询结果的列表达式(而您尝试执行除零错误的尝试就是证明)。

这取决于您选择的列,但也取决于列表达式的易变性类别。如果从未使用过优化器,则可以随意省略immutablestable调用函数,因为它们不会影响结果,但是volatile函数可能会产生副作用,因此它们不那么容易被优化掉,因此它们从未使用过。

例如:

create function stable_function() returns int as $$
begin
  raise notice 'stable_function() called';
  return 1;
end
$$
language plpgsql stable;

create function volatile_function() returns int as $$
begin
  raise notice 'volatile_function() called';
  return 1;
end
$$
language plpgsql volatile;

create view v as
  select stable_function(), volatile_function();

如果仅volatile选择该列:

test=# explain (analyse, verbose) select volatile_function from v;
NOTICE:  volatile_function() called
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Subquery Scan on v  (cost=0.00..0.27 rows=1 width=4) (actual time=0.057..0.057 rows=1 loops=1)
   Output: v.volatile_function
   ->  Result  (cost=0.00..0.26 rows=1 width=8) (actual time=0.056..0.056 rows=1 loops=1)
         Output: NULL::integer, volatile_function()

...然后如您所见,输出中stable_function()不存在该内容explain,并且缺少a NOTICE确认此调用已被优化。

但是,如果stable改为选择该列:

test=# explain (analyse, verbose) select stable_function from v;
NOTICE:  stable_function() called
NOTICE:  volatile_function() called
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Subquery Scan on v  (cost=0.00..0.52 rows=1 width=4) (actual time=0.139..0.139 rows=1 loops=1)
   Output: v.stable_function
   ->  Result  (cost=0.00..0.51 rows=1 width=8) (actual time=0.138..0.138 rows=1 loops=1)
         Output: stable_function(), volatile_function()

...然后,我们看到两个列表达式都出现在计划中,并且NOTICEs显示两个函数都已执行。

在文档中似乎没有明确提及此行为,因此对于是否将对表达式进行求值没有硬性保证,并且您不应该依赖函数调用可能产生的任何副作用。

但是,如果您唯一关心的是性能,那么只要您将功能标记为stableimmutable适当时,就可以合理地确定(尤其是在这种简单情况下)除非需要它们,否则不会对其进行评估。

(并且,当您在审核波动率声明时,可能还需要设置并行安全标志。)


1
“所以无论如何都会调用它”它将根据特定DBMS的保证来调用。其中可能没有。SQL查询描述的是结果,而不是过程。PostgesSQL文档重新发行:优化程序不对此类函数的行为做出任何假设。使用易失函数的查询将在需要其值的每一行重新评估该函数。(无论“需要”是什么意思。)
philipxy

@philipxy:你是绝对正确的。我并不是要暗示除文档中规定的那些保证之外的任何保证,尽管在重新阅读时,我确实做到了。希望我的编辑可以澄清问题。谢谢!
尼克·巴恩斯

4

您的猜想是正确的,如果不使用该列,则不应执行计算。

要确认这一点,请查看EXPLAIN (VERBOSE)查询的输出,该查询将向您显示返回的列。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.