2010-08-19 8 views
5

Ich habe eine Abfrage, die in etwa 5 Sekunden auf Postgres 8.4 ausgeführt wird. Er wählt Daten aus einer Ansicht aus, die mit anderen Tabellen verbunden ist, verwendet aber auch die Fensterfunktion lag(), d.Encapsulating Postgres Query in Sicht macht es extrem langsam

SELECT *, lag(column1) OVER (PARTITION BY key1 ORDER BY ...), lag(...) 
FROM view1 v 
JOIN othertables USING (...) 
WHERE ... 

Der Einfachheit halber habe ich eine neue Ansicht, die einfach

aus, dass
SELECT *, lag(column1) OVER (PARTITION BY key1 ORDER BY ...), lag(...) 
FROM view1 v 

und dann SELECT hat, mit all den anderen JOIN und Filter wie zuvor. Zu meiner Überraschung wird diese Abfrage nicht in 12 Minuten abgeschlossen (ich habe es an diesem Punkt gestoppt). Offensichtlich hat Postgres einen anderen Ausführungsplan gewählt. Wie bekomme ich es, das nicht zu tun, dh. Verwenden Sie den gleichen Plan wie in der ursprünglichen Abfrage? Ich hätte gedacht, dass eine Ansicht den Ausführungsplan nicht ändern sollte, aber anscheinend tut es das.

Edit: was mehr ist, fand ich, dass selbst wenn ich den Inhalt der ersten Ansicht in den zweiten kopieren immer noch nicht zurückgibt.

Edit 2: OK, ich habe die Abfrage ausreichend vereinfacht, um die Pläne zu veröffentlichen.

die Ansicht verwenden (diese Rückkehr nicht in jeder angemessenen Zeit):

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) 

Unter der Fensterfunktion aus dem Blick und setzt in die Abfrage selbst (dies liefert ab sofort):

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

So scheint es, dass in dem langsamen Fall es versucht, die Fensterfunktion auf alle Daten zuerst zu übernehmen und es dann filtern, was wahrscheinlich das Problem. Ich weiß nicht, warum es das tut.

+0

+1, aber ich vermute stark, dass Sie die '...' Teile ausfüllen müssen, bevor jemand diagnostizieren kann, was vor sich geht. – Edmund

+0

könnte ich, aber die Abfrage ist ziemlich komplex und ich müsste erklären, wie alle relevanten Tabellen auch aussehen. Meine Frage bezieht sich eher auf eine generische Lösung für diese eher spezifische Abfrage: Gibt es eine Möglichkeit, Postgres mitzuteilen, dass es eine Sicht "durchschaut" und denselben Abfrageplan verwendet, als ob ich die zugrunde liegende SQL direkt eingegeben hätte. – EMP

+1

Abfrage Ausführungspläne? EXPLAIN SELECT ... –

Antwort

2

Der Unterschied zwischen den beiden Plänen ergibt sich aus der Verbindung mit einem Aggregat. Dies verhindert die Verwendung eines geschachtelten Schleifenplans. Wenn Sie das Aggregat aus Ihrer Sicht verwenden, versetzen Sie sich in dieses ungünstige Szenario.

Dies zum Beispiel führt fast immer zu einem Merge oder Hash-Join-Plan auf den beiden von einem Top-n sortieren gefolgt Tabellen:

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

Vielleicht haben Sie eine Common Table Expression (CTE) statt einer Ansicht mit in Erwägung ziehen könnte . Ich kann helfen, die Abfrage in einer ähnlichen Weise wie die Verwendung einer Ansicht zu verdeutlichen, scheint aber den Ausführungsplan nicht auf die gleiche Weise zu beeinflussen.

Ich hatte ein ähnliches Problem in this question und mit einem CTE anstelle einer Ansicht machte den Ausführungsplan viel effizienter.