UPDATE Trigger oder INSERT Trigger

Probleme und Fragen zum Thema Trigger und Funktionen.

UPDATE Trigger oder INSERT Trigger

Beitragvon traxanos » Fr 14. Mai 2010, 18:05

HI,

ich habe eine Datentabelle. Auf dieser werden sehr viele Daten geändert bzw. hinzugefügt. Darüber entscheidet ein Unique-Constraint. Meine Frage ist, was ist sinnvoller.

Variante 1:
INSERT Trigger der den Unique-Fehler Captured und dann ein Update macht

Variante 2:
UPDATE mit einem BEFORE Trigger der schaut gibt es den Datensatz mit FOR UPDATE und dann entscheidet.

Variante 1 hat den Vorteil das es max 2 SQLs sind. Bei der 2ten sind es genau 2. Daher würde ich V1 bevorzugen. Ist das die bessere oder habe ich etwas übersehen. Außerdem laufen die Prozesse für den Import später parallel. Auf den ersten Blick sieht es nicht so aus, als würde die sich gegenseitig blockieren, oder?

Die Daten würde ich über 1 Insert mit vielen VALUES übergeben werden.
traxanos
Benutzer
 
Beiträge: 98
Registriert: Di 27. Mai 2008, 12:48

Beitragvon akretschmer » Fr 14. Mai 2010, 18:50

[quote="traxanos"][/QUOTE]

Dieses Rad wurde bereits erfunden:

PostgreSQL: Documentation: Manuals: PostgreSQL 8.4: Control Structures

Ich würde es so machen. Die TRIGGER-Lösungen von Dir sind höchstwahrscheinlich langsammer.


Andreas

Andreas
--
ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)

https://www.xing.com/profile/Andreas_Kretschmer7
Hosting-Provider mit PostgreSQL-Support gesucht? Mich fragen!
akretschmer
Erfahrener Benutzer
 
Beiträge: 5938
Registriert: So 29. Okt 2006, 14:35
Wohnort: Kaufbach, Sachsen, Germany, Germany

Beitragvon traxanos » Fr 14. Mai 2010, 18:58

Das Beispiel hatte ich auch schon überlegt. Allerdings gibt es bei mir noch ne Sonderheit. Ich hab eine Datum das darüber entscheidet ob geupdated wird oder nicht. Würde ich nu in der Where-Bedingung um die "Ist Aktueller?" Prüfung erweitern, würde ich hier einen Endless-Loop bauen.
traxanos
Benutzer
 
Beiträge: 98
Registriert: Di 27. Mai 2008, 12:48

Beitragvon traxanos » Fr 14. Mai 2010, 19:30

Ist den ein direkt Funktionsaufruf sehr viel schneller als ein Trigger, als Nennenswert?
traxanos
Benutzer
 
Beiträge: 98
Registriert: Di 27. Mai 2008, 12:48

Beitragvon akretschmer » Fr 14. Mai 2010, 20:15

traxanos hat geschrieben:Ist den ein direkt Funktionsaufruf sehr viel schneller als ein Trigger, als Nennenswert?


Müßte man testen. Wenn es viele Daten sind und es schnell gehen muß, gäbe es noch andere Wege. So z.B. die neuen Daten via COPY erst einmal in eine extra Tabelle packen und dann schauen, welche nun via INSERT und welche via UPDATE zu behandeln sind. COPY ist generell sehr schnell, und die extra Tabelle hätte weder TRIGGER noch Funktionsaufrufe. Der 'Rest' wäre dann simples SQL.

Andreas
--
ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)

https://www.xing.com/profile/Andreas_Kretschmer7
Hosting-Provider mit PostgreSQL-Support gesucht? Mich fragen!
akretschmer
Erfahrener Benutzer
 
Beiträge: 5938
Registriert: So 29. Okt 2006, 14:35
Wohnort: Kaufbach, Sachsen, Germany, Germany

Beitragvon traxanos » Fr 14. Mai 2010, 20:45

Also es werden nur Daten per ImportCron aus einer Datei verarbeitet. Somit lohnt die Zwischentabelle nicht. Ich würde halt nur gerne in die parallele gehen und grübel, ob die sich bei den erst Insert und dann Update.
Ob ich das als Trigger löse oder als Funktion ist denk ich mal, ist 2rangig. Ich kann auch beides machen, wobei als Trigger finde ich vom Verständnis her nachvollziehbar.
Was ich an der Insertlösung noch gut find ist, ich kann halt ein Insert mit mehren Values machen.

Bei der Lösung merge_db ist es überhaupt machbar abhängig von einem Datum das Update zu machen. Ich glaube ich müsste die Funktion vom Aufbau wie folgt anpassen

* Update mit Wherebedingung, um nur zu Updaten wenn der Datensatz älter ist.
* Dann schauen git es einen Datensatz ohne diese Where-Bedingung
* Dann versuche ein Insert

Hier hätte ich aber 3 SQLs wenn es ein Insert gibt. Insert werden wohl auch die häufigeren Statements sein.

Wie löst Postgres das? Es gibt ja keine Insert-Locks, stören sich die Inserts bei der parallelen Verarbeitung? Jeder Importvorgang läuft in einer Transaktion. Die DB muss doch auch sicherstellen, dass der Constraint safe ist.
traxanos
Benutzer
 
Beiträge: 98
Registriert: Di 27. Mai 2008, 12:48

Beitragvon akretschmer » Fr 14. Mai 2010, 21:17

traxanos hat geschrieben:Also es werden nur Daten per ImportCron aus einer Datei verarbeitet. Somit lohnt die Zwischentabelle nicht. Ich würde halt nur gerne in die parallele gehen und grübel, ob die sich bei den erst Insert und dann Update.
Ob ich das als Trigger löse oder als Funktion ist denk ich mal, ist 2rangig. Ich kann auch beides machen, wobei als Trigger finde ich vom Verständnis her nachvollziehbar.
Was ich an der Insertlösung noch gut find ist, ich kann halt ein Insert mit mehren Values machen.

Bei der Lösung merge_db ist es überhaupt machbar abhängig von einem Datum das Update zu machen. Ich glaube ich müsste die Funktion vom Aufbau wie folgt anpassen

* Update mit Wherebedingung, um nur zu Updaten wenn der Datensatz älter ist.
* Dann schauen git es einen Datensatz ohne diese Where-Bedingung
* Dann versuche ein Insert

Hier hätte ich aber 3 SQLs wenn es ein Insert gibt. Insert werden wohl auch die häufigeren Statements sein.

Wie löst Postgres das? Es gibt ja keine Insert-Locks, stören sich die Inserts bei der parallelen Verarbeitung? Jeder Importvorgang läuft in einer Transaktion. Die DB muss doch auch sicherstellen, dass der Constraint safe ist.


Fragen:

- laufen da mehrere solche Prozesse gleichzeitig?
- warum 'lohnt' sich Zwischentabelle nicht?
- über was für Datenmengen reden wir?
- Insert mit mehreren Values: Du meinst sicherlich ein Multi-row - Insert, oder? Aber ist denn vorher bekannt, ob alle Rows neu sind?
- Parse error im Satz "Bei der Lösung merge_db ist es überhaupt machbar abhängig von einem Datum das Update zu machen."

Zu Deiner Frage:

"Wie löst Postgres das? Es gibt ja keine Insert-Locks, stören sich die Inserts bei der parallelen Verarbeitung?"

Gegenfrage: hast Du es mal probiert?


Andreas
--
ads Das hatte dir akretschmer gestern schon gesagt und siehe da sobald du das machst, funktioniert es ;-)

https://www.xing.com/profile/Andreas_Kretschmer7
Hosting-Provider mit PostgreSQL-Support gesucht? Mich fragen!
akretschmer
Erfahrener Benutzer
 
Beiträge: 5938
Registriert: So 29. Okt 2006, 14:35
Wohnort: Kaufbach, Sachsen, Germany, Germany

Beitragvon traxanos » Fr 14. Mai 2010, 23:48

laufen da mehrere solche Prozesse gleichzeitig?

Jein, es wird nen Messagebus geben, der Aufgaben an Daemons verteilt. Wenn 5 Importe gleichzeitig angestoßen werden, laufen die 5 Imports gleichzeitig (je nachdem viele Worker gestartet sind). Ich denke mal das es maximal 3-4 Importaufträge sein werden.

über was für Datenmengen reden wir?

30-60k pro Lieferung. Insgesamt werde ich wohl vermutlich von einem Volumen über 50 Mio Datensätze ausgehen müssen, aber eher weniger.

warum 'lohnt' sich Zwischentabelle nicht?

Weil ich die Daten bereits in einer Tabelle (Ram) vorliegen habe und der Prozess ein Hintergrundprozess ist. Da kann auch der Hintergrundprozess etwas dauern. Und ein normaler MultiRow Insert mit 30-60k dauert nur einige Sekunden. Ich sehe also aktuell keinen Grund, was für einen Vorteil mir das verschaffen soll. Die Logik zum verarbeiten bleibt ja die gleiche.

Insert mit mehreren Values: Du meinst sicherlich ein Multi-row - Insert, oder? Aber ist denn vorher bekannt, ob alle Rows neu sind?

Korrekt MultiRow Insert war gemeint. Nein, daher dachte ich ja an einen Before-Trigger der dann entscheidet ob Insert oder Update (siehe Ursprungspost). Aber eine Funktion aufzurufen ala merge_db würde auch gehen. Dachte nur das ein Multirow Insert einfacher für den SQL Parser ist, als viele Einzelstatments. Außerdem hatte sich das in der Vergangenheit diese MultiRow Insert (Merhere Millionen Rows pro Insert in wenigen Minuten) sehr bewährt.

Parse error im Satz "Bei der Lösung merge_db ist es überhaupt machbar abhängig von einem Datum das Update zu machen."

Bei der Lösung "merge_db" -> Ist es überhaupt möglich hier ein Datum zu beachtet, das dafür sorgt das nur neuere Datensätze als Update zugelassen werden. Würde ich die Where-Bedingung blind erweiterung um die Datumsprüfung, würde ich nen Endless Loop bauen, weil weder das Update noch das Insert greifen würden. Einzige Möglichkeit ist ein extra Select und das würde 3 Aktionen bei einem Insert bedeuten.


Als Backgroundinfo:

Verschiedene Systeme liefern Daten an. Über einen Schlüssel können Daten geändert oder beim ersten mal angelegt werden. Allerdings dürfen die Daten nur mit neueren Daten überschrieben werden. Sprich jde Zeile hat ein Erstelldatum.

Gegenfrage: hast Du es mal probiert?


Ja und keine Störung fest gestellt. Allerdings ist das schwer praxisnah zu testet und kann mir nicht sicher sein, dass er intern vielleicht doch gewartet. Daher die Frage. Mann muss das Rad ja nicht neu erfinden, dafür ist das Forum hoffentlich da :D
traxanos
Benutzer
 
Beiträge: 98
Registriert: Di 27. Mai 2008, 12:48

Beitragvon traxanos » Di 18. Mai 2010, 12:59

So hab das nun so gelöst

Code: Alles auswählen
CREATE OR REPLACE FUNCTION import_tabelle(felder) RETURNS VOID AS
$$
BEGIN
  BEGIN
    INSERT INTO tabelle (felder) VALUES (values);
  EXCEPTION WHEN unique_violation THEN
    UPDATE tabelle SET values WHERE uniqfelder AND "updated_at" < new_updated_at;
  END;
END;
$$
LANGUAGE plpgsql;


Werde nun mal das mit Realdaten testen, aber die ersten Tests sahen perfekt aus.
traxanos
Benutzer
 
Beiträge: 98
Registriert: Di 27. Mai 2008, 12:48


Zurück zu Trigger und Funktionen

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste