2010-08-19 25 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而不是視圖使執行計劃更有效。