我试图了解从视图中选择数据的性能影响,其中视图中的一列是原始表中其他数据的函数。
无论计算列是否在所选列的列表中,是否都会执行计算?
如果我有一张桌子并且视图像这样声明
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
Run Code Online (Sandbox Code Playgroud)
会是乘法类似下面的查询来执行?
select ticker, ddate, price, factor from prices
Run Code Online (Sandbox Code Playgroud)
是否有参考以一种方式或另一种方式保证这一点?我正在阅读有关 Postgres 规则系统的文档,但我认为答案确实在于优化器,因为规则系统文档中没有任何内容表明它不会被选中。
我怀疑在上述情况下没有执行计算。我将视图更改为使用除法而不是乘法,并将0for插入factor到price_data. 上面的查询没有失败,但如果修改查询以选择计算列,则修改后的查询失败。
有什么方法可以理解在执行 a 时select正在执行哪些计算?我想我正在寻找类似EXPLAIN但也告诉我正在执行的计算的东西。
正如@Laurenz 所说,您的分析是正确的:优化器将避免评估不影响查询结果的列表达式(并且您试图强制除以零错误证明了这一点)。
这取决于您选择的列,但也取决于列表达式的波动率类别。如果从不使用它们的输出,优化器可以自由地省略immutable和stable函数调用,因为它们不会影响结果,但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();
Run Code Online (Sandbox Code Playgroud)
如果仅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()
Run Code Online (Sandbox Code Playgroud)
...然后如您所见,输出中stable_function()不存在explain,并且缺少 aNOTICE确认此调用已被优化掉。
但是,如果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()
Run Code Online (Sandbox Code Playgroud)
...然后我们看到计划中出现了两个列表达式,并且NOTICEs 表明两个函数都已执行。
文档中似乎没有明确提及此行为,因此对于是否计算表达式没有硬性保证,并且您不应该依赖函数调用可能具有的任何副作用。
但是,如果您唯一关心的是性能,那么只要您将函数标记为stable或immutable在适当的地方,您就可以合理地确定(尤其是在这样的简单情况下)除非需要它们,否则不会对其进行评估。
(当您在那里审核您的波动率声明时,您可能还想设置并行安全标志。)