Funktion zusätzlich aufrufen bei Select statement

Dein erster Versuch mit der RULE auf Select sah so aus, als ob Du an der Tatsache, daß da ein Select kommt, nix ändern könntest (Closed Sorce). Du kannst aber ganz offensichtlich auch auf eine VIEW oder eine Funktion umstellen. Was exakt hindert Dich, ganz simpel nun zuerst Deine Funktion und dann Dein eigentliches Select abzusetzen?

Schön ist das so oder so nicht, schön wäre, wenn das DB-System, aus dem die Daten kommen, bei Änderungen dort von sich aus schon dafür sorgen würde, daß in Deiner PG-DB, die hier nur als Client agiert, korrekte Daten sind.

Alle Versuche, dies via einer Funktion zu bündeln, führt letztendlich auch nur dazu, das man ja immer noch ein simples Select ausführen könnte, ohne daß vorher Dein refresh() aktiv wird (gut, revoke der Rechte für den Nutzer und eine Funktion mit security definer könnte dies verhindern…)

Mußt Du halt wissen, wo die Prioritäten für Dich liegen.


Andreas

wenn er allerdings die beiden geschichten parallel abarbeitet waere das kein gutes ding …

dann koennte man allerdings versuchen das refresh() in einer subquery unterzubringen

symbiont,

Ich finde Deine Idee mit dem UNION im Prinzip super und habe ein paar Tests gemacht. Leider ist das

SELECT * FROM tabelle

immer schneller als die Funktion. D.h. erst beim zweiten Aufruf zeigt es die richtigen Werte an. Das ändert auch nicht, wenn ich die Reihenfolge vertausche.

Mit dem subquery hab ich leider auch das gleiche Problem wie Tests zeigen.

CREATE VIEW schema.view AS 
SELECT * 
from schema.tabelle
WHERE id not in 
(SELECT id FROM schema.refresh());

scheiss postgres :slight_smile: … da müssen wir noch ein bisschen experimentieren … es gibt ja noch ein paar moeglichkeiten ein subselect oder vielleicht auch einfch nur die simple refresh() funktion zu platzieren …

da muessen wir aber nochmal genau studieren wie man PG mithilfe von solchen abhaengigkeiten austricksen koennte

hmm - aber warum der bei dem subselect “schneller” ist … als was … ja warum eigentlich … so ganz versteh ich das noch nicht … oder ich hab dein refresh-problem noch nicht verstanden … moment

es koennte auch sein, dass das problem nicht “schneller” ist … sondern dass wir ein transaktionsproblem haben … also das was das refresh synchronisiert fuer das selekt in dem gleichen athemzug der db nicht sichtbar ist … hmm - bin mir hier aber net sicher … muss ich mal testen

kannst du das mit dem “schneller” nochmal ein bisschen erlaeutern … also was “genau” soll das refrehs tun, was das selekt hernach auch sehen soll ?!

Du meinst, in der Applikation später? Das stimmt zwar schon, aber das Replizieren ist nur eine Übergangslösung, damit ich jetzt schon gegen die PostgreSQL programmieren kann. Die Sybase Datenbank wird später abgesetzt. :slight_smile:

Natürlich. Könnte man mit Messages machen wie mal schon erwähnt wurde, aber die müssten “reliable” sein. Da gefällt mir die Idee mit dem polling besser ehrlich gesagt. Dann könnte man auch den Polling Prozess überwachen lassen. Auf der Sybase Seite ist ein WIN2000 Server an dem ich eigentlich nicht viel machen will.

also … es scheint tatsaechlich durch die Transaktion vom selekt isoliert zu werden …

das select startet -> snapshot
refresh -> insert insert insert update etc … was aber NOCH nicht sichtbar für die TX an dieser stelle ist
-> resultset sieht nur snapshot

beim naechstn aufruf der geschichte siehst dann das ergebnis des vorhergehenden refreshs…

ich hab das mal mit meinem beispiel probiert … fuege in meiner fkt einfach mmer eine zeile ein … ich sehe aber immer nur die vorletzte vom vorhergehenden aufruf

Also eigentlich gehört das Konzept zum “lazy load” Pattern. D.h. die pg Datenbank wird erst aktualisiert, sobald ein SELECT auf pg gemacht wird. D.h. auf Sybase Seite ist eine Cache Tabelle, welche alle INSERTS, UPDATES speichert und wenn nun ein Client eine Abfrage auf pg macht, schaut das System bei Sybase nach ob die pg Datenbank noch aktuell ist. Wenn nein, wird die Tabelle aktualisiert und dann sollten die Befehle direkt auf die frische Tabelle angewendet werden.

was du hier aber machen koenntest …

das refresh sollte also nicht NICHTs liefern - sondern einfach alle synchronisierten rows …

mit INSERT … RETURNING kriegst ja die row zu rueck …

hier :

CREATE OR REPLACE RULE "_RETURN" AS
    ON SELECT TO vtable DO INSTEAD  
    SELECT * from refresh()
    UNION
    SELECT * from atable

;

REATE OR REPLACE FUNCTION refresh()
  RETURNS SETOF atable AS
$BODY$  
DECLARE r RECORD;
BEGIN
    INSERT INTO atable VALUES(DEFAULT) RETURNING * INTO r;
    RETURN NEXT r;
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE STRICT
  COST 10; ROWS 1;

tut bei mir … hat natuerlich das problem, dass du zu updatende rows doppelt kriegen wirst :slight_smile: da kannst dir aber was einfallen lassen … das zu distincten …

vielleicht ist das aber je nach problem auch garnicht noetig :slight_smile:

hmm … auch wenn das problem zu loesen eine interessante sache ist … aber warum muss das immer taufrisch vor dem selekt sein?

Weil, sonst geht vielleicht ein Güterwagen anstatt nach Florenz nach Milano. :wink: Und dann krieg ich Ärger.

Das ist leider super langsam in pl/Perl. Braucht fast 1 sec (+ viel CPU) um 10’000 Werte von der pg Datenbank zu retournieren. Und ich brauche die DBI Schnittstelle.

also … bei soeinem refresh … wieviele Datensaetze werden im schnitt synchronisiert ?

NUR diese datensaetze soll die funktion liefern … die anderen kommen aus der anderen table …

d.h. im guenstigsten fall (nix ist zu synchronisieren) wuerde die funktion keine rows returnieren muessen

CREATE OR REPLACE FUNCTION refresh()
  RETURNS SETOF atable AS
$BODY$  
DECLARE r RECORD;
BEGIN
    UPDATE atable SET nr = -nr WHERE id = 38;
    SELECT * INTO r FROM atable WHERE id = 38;
    RETURN NEXT r;
    INSERT INTO atable VALUES(DEFAULT) RETURNING * INTO r;
    RETURN NEXT r;
END;
$BODY$
  LANGUAGE 'plpgsql' volatile STRICT
  COST 10
  ROWS 1;


dazu
CREATE OR REPLACE VIEW vtable AS 
   SELECT * FROM refresh()
  UNION 
  SELECT * FROM atable
  

und
select * from vtable

ergibt :
38;-1
38;1
39;1

also noch paar tips … und moeglichkeiten die ich aber jetzt nicht probieren moechte - muss gleich weg

wenn du die funktion als IMMUTABLE deklarierst - koennte man erreichen, dass Postgres sie nur einmal pro query … aufruft

An IMMUTABLE function cannot modify the database and is guaranteed to return the same results given the same arguments forever. This category allows the optimizer to pre-evaluate the function when a query calls it with constant arguments. For example, a query like SELECT … WHERE x = 2 + 2 can be simplified on sight to SELECT … WHERE x = 4, because the function underlying the integer addition operator is marked IMMUTABLE.

fuer pl/pqsql heisst das aber, dass da keine INSERTs drinnen vorkommen duerfen … aber man koennte ja wieder tricksen - und dynamisches sql verwenden also EXECUTE …

dann koenntest du z.B. in dem select auf die table das gleiche refresh() nochmal aufrufen um all die rows auszublenden, die von refresh() voher aktualisiert wurden … er soltle das dann an dieser stelle kein 2. mal ausfuehren sondern das result verwenden …

Nicht sehr viel, max. 100 denk ich mal.

Und dann ein Union machen… Sehr gute Idee! Probier ich gleich aus!

Zusatz: Also das Problem ist natürlich immer noch da, wenn plötzlich das SELECT * from pg.tabelle langsamer wäre als die Funktion. Weil, ich möchte ja so oder so die neuen Werte in der pg Tabelle haben und das würde ich zusätzlich in der Funktion machen. Oder seh ich da was falsch?


[/quote]

sehr wahrscheinlich gibt es das problem nicht … wie ich bereits sagte - da war nix schneller - nur die synchronisierten records sieht das select auf die table noch nicht … es sieht nur den stand “vorher” … dank transaktionen