--
https://www.xing.com/profile/Andreas_Kretschmer7ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
Natürlich zwingt mich keiner zu irgend was, der Faktor 25 sollte auch nur den Performanceverlust durch die Tabellen statt Variablen verdeutlichen.
Allerdings würde es mich als Freund von Open Source - Produkten doch schon freuen, wenn diese im Vergleich zu kommerziellen Produkten gut da stehen
Hintergrund: Ich mache gerade ein studentisches Praktikum und meine Aufgabe ist ein Performance-Vergleich Informix vs. Postgres bzgl. der hier benötigten Datenbankanforderungen. Bisher steht Postgres v.a. in Bezug auf die Performance ausgesprochen gut da ... daher verwundert bzw. stört mich dieses Problem doch ein wenig.
Zurück zum Problem:
Also die Funktion selbst ist ja in C geschrieben und liefert ordnungsgemäß die gewünschte Tabelle zurück. Wenn ich die Tabellen (hier t_temp_keys_a u.s.w.) zum zwischenspeichern verwende funktioniert ja auch alles.
Nur wenn ich die Variablen (keys_a, u.s.w.) verwende bekommt die FOR-Schleife nur einen Wert. Daher meine Vermutung das ich bei der Zuweisung der Funktionsrückgabe in die Variable bzw. in der FOR-Schleife einen Fehler habe ... auch wenn PG nichts anzeigt.
Code:... /* INSERT INTO t_temp_keys_a VALUES (hmGetMatchKeys( 'A', a1, a2, 'A*', dna_a1, dna_a2, pop_id, threshold )); INSERT INTO t_temp_keys_b VALUES (hmGetMatchKeys( 'B', b1, b2, 'B*', dna_b1, dna_b2, pop_id, threshold )); INSERT INTO t_temp_keys_dr VALUES (hmGetMatchKeys( 'DR', dr1, dr2, 'DRB1*', drb11, drb12, pop_id, threshold )); */ SELECT hmGetMatchKeys( 'A', a1, a2, 'A*', dna_a1, dna_a2, pop_id, threshold ) INTO keys_a; SELECT hmGetMatchKeys( 'B', b1, b2, 'B*', dna_b1, dna_b2, pop_id, threshold ) INTO keys_b; SELECT hmGetMatchKeys( 'DR', dr1, dr2, 'DRB1*', drb11, drb12, pop_id, threshold ) INTO keys_dr; FOR cur_a IN SELECT keys_a LOOP FOR cur_b IN SELECT keys_b LOOP cnt := 0; FOR cur_dr IN SELECT keys_dr LOOP ...
Nein. Schau:
t ist eine RECORD-Variable, sie speichert keine Tabelle, sondern 'nur' eine Zeile.Code:test=# select * from foo; id | word ----+----------- 1 | car 1 | fruit 2 | car 2 | fruit 3 | car 3 | vegetable 2 | vegetable 1 | car (8 rows) Time: 0.779 ms test=*# create function get_all() returns setof text as $$declare t record;begin for t in select word from foo loop return next t.word; end loop; end;$$language plpgsql; CREATE FUNCTION Time: 1.883 ms test=*# select * from get_all(); get_all ----------- car fruit car fruit car vegetable vegetable car (8 rows)
Andreas
--
https://www.xing.com/profile/Andreas_Kretschmer7ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
Ich fürchte ich drücke mich falsch oder undeutlich aus ... oder ich blicke es einfach nicht ( was wohl eher zutrifft).
Mit SELECT * FROM hmGetMatchKeys( ... Parameter ...); bekomme ich auch meine gewünschte Tabelle zurück, wie in Deinem Beispiel.
Genau diesen Inhalt möchte ich aber in meiner zweiten Funktion für die verschachtelten FOR-Schleifen nutzen und zwar ohne jedesmal wieder die Funktion hmGetMatchKeys( ... Parameter ...) aufrufen zu müssen.
Daher Suche ich einen Weg die mit der Funktion ermittelte Grundgesamtheit durch die meine Schleifen iterieren sollen,so zwischen zu speichern, das die geschachtelten Schleifen öfter darauf zugreifen können.
Ich brauche also irgend was im Sinne von:
Sorry für die Mühe ... und vielen Dank für die Geduld ...Code:FOR cur_a IN variable_mit_tabelle LOOP
keine Ahnung...
Eine SRF (Set Returning Function) liefert Dir quasi eine Tabelle. Mit der kannst Du wieder wie mit einer 'normalen' Tabelle arbeiten. Ausgehend von meinem Beispiel:Daher Suche ich einen Weg die mit der Funktion ermittelte Grundgesamtheit durch die meine Schleifen iterieren sollen,so zwischen zu speichern, das die geschachtelten Schleifen öfter darauf zugreifen können.
Hilft das?Code:test=*# select upper(foo) from get_all() foo; upper ----------- CAR FRUIT CAR FRUIT CAR VEGETABLE VEGETABLE CAR (8 rows)
Andreas
--
https://www.xing.com/profile/Andreas_Kretschmer7ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
Hallo Andreas,
super Idee ... so wie ich das verstehe löst das aber leider nicht mein Problem.
Ich führe den gravierenden Performance-Unterschied auf das entstehende Skalar in Bezug auf die Funktionsaufrufe zurück.
Nehmen wir an das jede Function eine Tabelle mit nur 10 Relationen zurückgibt:
In diesem Beispiel wären zum Abarbeiten aller schleifen also insgesamt 111 Funktionsaufrufe notwendig. Wenn ich das Ergebnis der drei Funktionen in Variablen halten könnte (so wie es bei Informix implementiert wurde) sind es halt nur 3 Funktionsaufrufe.Code:FOR a IN SELECT * FROM function_a() LOOP <--- 1x | FOR b in SELECT * FROM function_b() LOOP <--- 10x | FOR c IN SELECT * FROM function_c() LOOP <--- 100x ... END LOOP; END LOOP; END LOOP;
Ich werde als nächstes mal den CREATE FUNCTION - Statements der drei Funktionen mal ein 'IMMUTABLE' spendieren ... in der Hoffnung, da noch etwas Zeit einzusparen. (Hätte ich eigentlich auch schon früher machen können...)
Interessehalber lasse ich die ganze Sache mal mit den Attributen IMMUTABLE | STABLE und VOLATILE laufen, um den Performance-Unterschied zu messen.
Und wenn alles nichts hilft, werde ich mal versuchen die Funktion mit den Schleifen in Perl zu implementieren ... da kann man ja Tabellen in Variablen packen.
Viele Grüße,
Andreas
[QUOTE=kiaaap;7575]Hallo Andreas,
super Idee ... so wie ich das verstehe löst das aber leider nicht mein Problem.
Ich führe den gravierenden Performance-Unterschied auf das entstehende Skalar in Bezug auf die Funktionsaufrufe zurück.
In diesem Beispiel wären zum Abarbeiten aller schleifen also insgesamt 111 Funktionsaufrufe notwendig. Wenn ich das Ergebnis der drei Funktionen in Variablen halten könnte (so wie es bei Informix implementiert wurde) sind es halt nur 3 Funktionsaufrufe.
[code]
Dann erzeuge Arrays aus dem Resultat, also sowas wie:
In Deiner Funktion rufst Du dann halt nur einmalig die SRF auf und kippst das in Arrays, die Du dann mit den Arrayfunktionen durchlaufen kannst.Code:test=# CREATE AGGREGATE array_accum ( test(# sfunc = array_append, test(# basetype = anyelement, test(# stype = anyarray, test(# initcond = '{}' test(# ); CREATE AGGREGATE test=*# commit; COMMIT test=# select * from foo; id | t ----+----- 5 | 1,2 6 | 2,2 7 | 3,2 1 | 1 1 | 1 (5 rows) test=*# select array_accum(id), array_accum(t) from foo; array_accum | array_accum -------------+------------------------- {5,6,7,1,1} | {"1,2","2,2","3,2",1,1} (1 row)
Andreas
--
https://www.xing.com/profile/Andreas_Kretschmer7ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)
Hallo Andreas,
ich habe inzwischen meine Funktion mit den FOR-Schleifen nochmal in Perl geschrieben, denn eine externe Bibliothek auf die ich in jedem Durchgang zugreifen muss basiert auch auf Perl ... da bot es sich einfach an diesen Weg zu gehen. Ich habe allerdings Deinen letzten Vorschlag mit in unsere Doku aufgenommen, um diese Vorgehensweise bei anderen Matching-Schleifen zu nutzen.
Perl-Version:
Die Performance ist nun auch schon viel erfreulicher. Aus Faktor 25 wurde Faktor 4 .Code:my $keys_a = hmGetMatchKeys( "A", $a1, $a2, "A*", $dna_a1, $dna_a2, $pop_id, $threshold ); my $keys_b = hmGetMatchKeys( "B", $b1, $b2, "B*", $dna_b1, $dna_b2, $pop_id, $threshold ); my $keys_dr = hmGetMatchKeys( "DR", $dr1, $dr2, "DRB1*", $drb11, $drb12, $pop_id, $threshold ); foreach my $key_a ( @$keys_a ) { foreach my $key_b ( @$keys_b ) { foreach my $key_dr ( @$keys_dr ) {
Vermutlich hat Informix noch die Nase vorn, weil es besagte Perl-Bibliothek nach dem ersten Aufruf permanent im Speicher hält, während Postgres vermutlich bei jedem Funktionsaufruf die Bibliothek neu lädt.
Das ist bei Informix natürlich ganz toll für die Performance ... allerdings muss bei jedem Update der Bibliothek der Server neu gestartet werden (nicht so toll).
Gibts da bei Postgres vielleicht einen eleganteren Weg, eine geladene Bibliothek für längere Zeit (sprich über eine Session hinaus) im Speicher zu halten ?
Links: Tobias Bauer - IT- und Funkdienstleistungen - Bilderrahmen-kaufen.de - Der Onlineshop für Bilderrahmen & Fotorahmen - Funkforum
Lesezeichen