Performance 在视图中封装Postgres查询会使其速度非常慢

Performance 在视图中封装Postgres查询会使其速度非常慢,performance,postgresql,view,window-functions,Performance,Postgresql,View,Window Functions,我有一个在Postgres 8.4上运行大约5秒钟的查询。它从连接到其他一些表的视图中选择数据,但也使用lag()窗口函数,即 SELECT *, lag(column1) OVER (PARTITION BY key1 ORDER BY ...), lag(...) FROM view1 v JOIN othertables USING (...) WHERE ... 为了方便起见,我创建了一个新的视图 SELECT *, lag(column1) OVER (PARTITION BY ke

我有一个在Postgres 8.4上运行大约5秒钟的查询。它从连接到其他一些表的视图中选择数据,但也使用lag()窗口函数,即

SELECT *, lag(column1) OVER (PARTITION BY key1 ORDER BY ...), lag(...)
FROM view1 v
JOIN othertables USING (...)
WHERE ...
为了方便起见,我创建了一个新的视图

SELECT *, lag(column1) OVER (PARTITION BY key1 ORDER BY ...), lag(...)
FROM view1 v
然后像以前一样使用所有其他联接和筛选器从中进行选择。令我惊讶的是,这个查询并没有在12分钟内完成(我当时就停止了)。显然,Postgres选择了不同的执行计划。我如何让它不这样做,即使用与原始查询中相同的计划?我本以为视图不应该改变执行计划,但显然它确实如此

编辑:更重要的是,我发现即使我将第一个视图的内容复制到第二个视图中,它仍然不会返回

编辑2:好的,我已经充分简化了查询,可以发布计划了

使用视图(在任何合理的时间内都不会返回):

将窗口函数从视图中取出并放入查询本身(这会立即返回):


因此,在慢速情况下,它似乎试图首先将窗口函数应用于所有数据,然后对其进行过滤,这可能就是问题所在。不过,我不知道它为什么会这样做。

这两个计划之间的区别在于使用了一个聚合。这将防止使用嵌套循环计划。当您在视图中使用聚合时,您将自己置于不利的场景中

例如,这几乎总是导致两个表上的合并或哈希连接计划,然后是top-n排序:

select foo.*
from foo
join (select bar.* from bar group by bar.field) as bar on foo.field = bar.field
where ...
order by bar.field
limit 10;

也许你可以考虑用A代替视图。我可以用与使用视图类似的方式帮助使查询更清晰,但似乎不会以同样的方式影响执行计划


我在使用CTE而不是视图时遇到了类似的问题,这使得执行计划更加高效。

+1,但我强烈怀疑,在有人能够诊断出发生了什么之前,您需要填写
部分。我可以,但如果查询相当复杂,我还必须解释所有相关表的外观。我的问题更多的是关于这个特定查询的通用解决方案:有没有一种方法可以告诉Postgres“查看”一个视图并使用相同的查询计划,就像我直接输入底层SQL一样。Post query执行计划?解释选择…我用一些类似于你的不完整陈述的东西测试了这个,但没有什么区别。“从视图中选择”和“从表中选择”之间的“相同时间和执行计划”直接为我们提供这两个计划,以便我们可以查看是否有任何更改。
WindowAgg  (cost=34.91..34.95 rows=7 width=129)
  ->  Sort  (cost=34.91..34.92 rows=7 width=129)
        Sort Key: sp.stock_id, sp.price_date
        ->  Nested Loop  (cost=0.00..34.89 rows=7 width=129)
              ->  Index Scan using stocks_ticker_unique on stocks s  (cost=0.00..4.06 rows=1 width=18)
                    Index Cond: ((ticker)::text = 'Some Ticker'::text)
                    Filter: ((ticker)::text ~~ 'Some Ticker'::text)
              ->  Index Scan using stock_prices_id_date_idx on stock_prices sp  (cost=0.00..30.79 rows=14 width=115)
                    Index Cond: ((sp.stock_id = s.stock_id) AND (sp.price_date >= '2010-06-01'::date))
select foo.*
from foo
join (select bar.* from bar group by bar.field) as bar on foo.field = bar.field
where ...
order by bar.field
limit 10;