2017-10-25 1 views
0

Ich habe ein fucntion pb(IDCODE,0) es mit IDCODE=320 Lauf gibt diese Daten Beispiel:wie kann ich beschleunigen Abfrage mit 3 Funktion in PostgreSQL ruft

select * 
from pb(320,0) 



logid entrydate qty 
1  1.10.17 5 
2  1.10.17 6 
3  1.10.17 5 
4  1.10.17 -3 
5  2.10.17 6 
6  3.10.17 -100 

* es gibt tatsächlich mehr Zeilen (wie 20000), aber ich reduziert es für Das Beispiel

Pb ist eine sehr schwere Funktion, aber in einfachen Worten zeigt es Aktivitäten auf der Grundlage ihrer Reihenfolge.

Ich möchte die entrydate der ersten Vorkommen von qty<0 nach der letzten Zeile von qty>0 finden.

Um das zu tun, dass ich so etwas wie dies tun müssen:

Select Min(logid) where qty<0 and logid>(select max(logid) where qty>=0) 

In dem obigen Beispiel das angeforderte Ergebnis ist 3.10.17 Denn:

logid=5 ist max(logid) where qty>=0

und

logid=6 ist Min(logid) where qty<0 and logid>(select max(logid) where qty>=0) die in der Tat: Select Min(logid) where qty<0 and logid>5

Also schrieb ich die folgende Abfrage:

select entrydate 
from pb(320,0) 
where logid= ( SELECT min(logid) 
        FROM pb(320,0) 
        where qty<0 and logid>(SELECT coalesce(max(logid),0) 
              FROM pb(320,0) 
              WHERE qty >= 0)) 

Dies funktioniert gut, aber es ist 3 Mal, dass ich die Funktion pb(320,0) nennen.

Es ist riesig zeitaufwendig und unnötig zu sagen, dass ich diese Abfrage tatsächlich laufen auf vielen IDCODES (wie 214) so ​​pb(IDCODE,0) tatsächlich läuft 214*3 diese schrecklich.

Was kann ich tun?

+1

Wenn sich die Ausgabe der Funktion nicht in einer einzelnen Anweisung ändert, ändern Sie die Flüchtigkeit der Funktion in stable und vergleichen Sie die Ergebnisse. – JustMe

+0

Die Funktion in eine VIEW umschreiben? BTW: Was ist in der Funktion? – wildplasser

+1

PostgreSQL verliert manchmal eine Menge Leistung bei Unterauswahlen. In Funktionen sollten Sie besser Ergebnisse in Variablen zuweisen (zB 'SELECT max() INTO maxValue ...') und die Variable in einer einfacheren Abfrage verwenden. Nur meine zwei Cent. –

Antwort

2

Verwenden Sie zunächst einen CTE, da Postgres möglicherweise den CTE realisiert.

Allerdings müssen Sie nur eine Tabelle Bezug, wenn Sie Fensterfunktionen verwenden:

with t as (
     select * 
     from pb(320,0) 
    ) 
select t.* 
from (select t.*, max(case when qty > 0 then logid end) over() as last_poslogid 
     from t 
    ) t 
where id > last_poslogid and qty < 0 
order by id 
fetch first 1 row only; 

Neuere Versionen von Postgres unterstützen die filter Klausel, die ein bisschen effizienter als die case ist.

Verwandte Themen