Einfügen großer Mengen von Tupeln in Tabellen

Hallo,

ich habe zwei Relationen, die auszugsweise in etwa wie folgt aussehen:

CREATE relation1 (id SERIAL PRIMARY KEY, name VARCHAR(20)); und
CREATE relation2 (id SERIAL PRIMARY KEY, id_relation1 INT4 REFERENCES relation1(id));

CREATE INDEX relation1_name_idx ON relation1 (name varchar_pattern_ops);

Der Ablauf: Falls noch nicht vorhanden, füge ich in relation1 einen neuen Namen hinzu. Die ID des Namens füge ich anschließend in relation2 ein.

Diese Prozedur muß in einer Client-Anwendung automatisiert ca. 20.000 Mal durchgeführt werden. Mich interessiert nun: Wie optimiere ich diesen Vorgang? Der User der Client-Anwendung soll natürlich eine möglichst geringe Wartezeit haben.

Sollten mehr Informationen benötigt werden, bitte fragen…

MfG, eazy

P.S.: Bin neu hier, sollte dieser Thread im falschen Forum gelandet sein, bitte verschieben. Da es sich bei der Client-Anwendung allerdings um ein in Java geschriebenes Programm handelt, habe ich erstmal hier begonnen…

Hallo eazy,

deine Lösung könnte wie folgt aussehen:

CREATE TRIGGER          tr_relation1
AFTER                   INSERT
ON                      relation1
FOR EACH                ROW
EXECUTE PROCEDURE       update_relation2 ();



CREATE OR REPLACE FUNCTION update_relation2 ()
RETURNS trigger

AS $BODY$

  BEGIN

    insert into relation2 (id_relation1) VALUES (NEW.id);
    return NEW;

  END;

$BODY$

LANGUAGE plpgsql;

mfg

fristo

Hallo,

erstmal vielen Dank für die schnelle Hilfe (hier scheint ja wirklich was los zu sein, juhu…). So ganz glücklich bin ich mit dem Lösungsvorschlag allerdings noch nicht.

In meinem Fall ist es nämlich auch durchaus möglich, dass ein Eintrag in relation2 gemacht werden muß, wenn sich an relation1 nichts ändert. Ich dachte daher an eine Prozedur, deren Body in etwa wie folgt aussehen könnte…

SELECT INTO id_1 id FROM relation1 WHERE name LIKE $$1;
IF NOT FOUND THEN
    INSERT INTO relation1 (name) VALUES ($$1);
END IF;
SELECT INTO id_1 id FROM relation1 WHERE name LIKE $$1;
IF FOUND THEN
    INSERT INTO relation2 (id_relation1) VALUES (id_1);
END IF;

Aber geht es vielleicht auch schneller? Mein Problem ist, dass der User ja prinzipiell nicht so gerne 20.000 mal x Millisekunden wartet, bis die entsprechenden Daten eingefügt sind. Für eine optimierte Lösung wäre ich sehr dankbar! :wink:

Gruß, eazy

Als erstes sollte man das ganze in eine Transaktion kapseln. Die wird zum Schluss commited (aber auch darauf achten, das nicht zuviel Speicher verbraucht wird auf dem Db Host).
Das dürfte den deutlichsten Performanceschub bringen.

Überlegenswert wäre auch, den Index zu droppen und hinterher neu zu erstellen. Dann wird er einmal aus den Daten der Tabelle gefüllt, nicht bei jedem Write geupdated.

Hallo eazy,

Hättest Du sein können, wenn Du die Randbedingungen vollständig beschrieben hättest.



Der beschriebene Trigger stellt immer sicher, dass beim Einfügen eines neuen Datensatzes in relation1 auch der entsprechende Datensatz in relation2 eingefügt wird. Damit hast Du die Referenz sichergestellt. Ein zusätzlicher Eintrag in relation2 bedeutet Mehrfachreferenzen. Zudem ist es ein ganz anderer Vorgang, da die Triggerfunktion nur einmal per Datensatz, direkt nach den Einfügen, ausgeführt wird.



Na, ja, Du kannst Dich ja mal mit dem COPY FROM Befehl befassen. Ich würde damit aber vorsichtig sein, da das Einfügen der Daten bei Dir von einem User erfolgen soll. Zudem stellt sich auch die Frage, wie oft das Einfügen von 20000 Datensätzen erfolgt. Und die Konsistenz einer Datenbank sollte immer Priorität 1 haben.



mfg

fristo

Also ich nehme mal an, du hast das DB-Schma normalisiert, oder?
Wenn du pro Tag mehrmals 20.000 Datensätze einfügst, dann
wird die schonmal was langsamer, das wäre ja in einem Jahr
bei 3 mal pro Tag:

365 * 3 * 20.000 = 21.360.000 neue Datensätze ist das wahr?

Aber das war ja gar nicht deine Frage, wollte das nur mal kurz
ansprechen.

Also, den Index zu droppen und nach dem Einfügen neu aufzubauen,
müsste schon deutlich schneller machen, da nach jeder
Einfüge-Operation der Index neu aufgebaut wird.
Schneller könnte es auch mit einer Stored Procedure werden (Also
einer gespeicherten Abfrage, der du nur noch die Werteliste
übergibst).

Müssen denn die Anwender jedesmal sehen, wenn die Datensätze ein-
gefügt wurden, oder kann das evtl. im Hintergrund erfolgen? Da
gibts bestimmt ne möglichkeit mit nem 2. Programm, dass nur zum
Einfügen benutzt wird.


Gruß
Yves