2010-08-19 29 views
5

我有一个在Postgres 8.4上运行约5秒的查询。它从加入其他表格的视图中选择数据,但也使用窗口函数(即,)。封装Postgres查询视图使其非常缓慢

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:好的,我已经简化了查询,足以发布计划。

使用视图(这不以任何合理的时间返回):

Subquery Scan sp (cost=5415201.23..5892463.97 rows=88382 width=370) 
    Filter: (((sp.ticker)::text ~~ 'Some Ticker'::text) AND (sp.price_date >= '2010-06-01'::date)) 
    -> WindowAgg (cost=5415201.23..5680347.20 rows=53029193 width=129) 
     -> Sort (cost=5415201.23..5441715.83 rows=53029193 width=129) 
       Sort Key: sp.stock_id, sp.price_date 
       -> Hash Join (cost=847.87..1465139.61 rows=53029193 width=129) 
        Hash Cond: (sp.stock_id = s.stock_id) 
        -> Seq Scan on stock_prices sp (cost=0.00..1079829.20 rows=53029401 width=115) 
        -> Hash (cost=744.56..744.56 rows=29519 width=18) 
          -> Seq Scan on stocks s (cost=0.00..744.56 rows=29519 width=18) 

以窗函数出来的观点,并付诸查询本身(这将返回瞬间):

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)) 

如此看来,在缓慢的情况下,它试图将窗函数首先适用于所有数据,然后将其过滤,这可能是问题。不过,我不知道为什么会这样做。

+0

+1,但我强烈怀疑你需要填写'...'部分,然后才能有人诊断发生了什么。 – Edmund 2010-08-20 00:35:11

+0

我可以,但查询如果相当复杂,我不得不解释所有相关表的样子。我的问题更多的是关于这个具体查询的通用解决方案:是否有办法告诉Postgres“查看”一个视图并使用相同的查询计划,就像我直接输入底层SQL一样。 – EMP 2010-08-20 01:28:00

+1

发布查询执行计划? EXPLAIN SELECT ... – 2010-08-20 01:28:56

回答

2

这两个计划之间的区别来自加入聚合。这可以防止使用嵌套的循环计划。当你在视图中使用聚合时,你会陷入这种不利的情况。

此,例如,几乎总是导致合并或哈希联接计划的两个表,然后顶-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; 
0

也许你可以考虑使用一个Common Table Expression (CTE),而不是一个视图。我可以帮助使查询更加清晰,类似于使用视图,但似乎不会以同样的方式影响执行计划。

我在this question有类似的问题,并使用CTE而不是视图使执行计划更有效。