Ergebnis 1 bis 7 von 7

Thema: Einfügen großer Mengen von Tupeln in Tabellen

  1. #1
    eazy ist offline Neuer Benutzer
    Registriert seit
    29.06.2006
    Ort
    Braunschweig
    Beiträge
    19

    Standard 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...

  2. #2
    fristo ist offline Super-Moderator
    Registriert seit
    08.12.2005
    Ort
    Raum Frankfurt/Main
    Beiträge
    668

    Standard

    Hallo eazy,

    deine Lösung könnte wie folgt aussehen:

    Code:
    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

  3. #3
    eazy ist offline Neuer Benutzer
    Registriert seit
    29.06.2006
    Ort
    Braunschweig
    Beiträge
    19

    Standard

    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...

    Code:
    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! ;-)

    Gruß, eazy

  4. #4
    ads
    ads ist offline Super-Moderator
    Registriert seit
    08.02.2006
    Ort
    MD
    Beiträge
    4.056

    Standard

    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.
    Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören

    Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler

    PostgreSQL Service & Support

  5. #5
    fristo ist offline Super-Moderator
    Registriert seit
    08.12.2005
    Ort
    Raum Frankfurt/Main
    Beiträge
    668

    Standard

    Hallo eazy,

    Zitat Zitat von eazy
    So ganz glücklich bin ich mit dem Lösungsvorschlag allerdings noch nicht.
    Hättest Du sein können, wenn Du die Randbedingungen vollständig beschrieben hättest.



    Zitat Zitat von eazy
    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.
    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.



    Zitat Zitat von eazy
    Ich dachte daher an eine Prozedur, deren Body in etwa wie folgt aussehen könnte...

    Code:
    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;
    Vergess den Code und verwende den beschriebenen Trigger. Es geht einfacher: Lege den PK auf "name". Wenn Du dann folgenden Code ausführst

    Code:
    BEGIN;
    INSERT INTO relation1 (name) VALUES (xxxx);
    COMMIT;
    erhälst Du eine Fehlermeldung, falls xxxx schon in relation1 vorhanden ist, anderenfalls werden die neuen Daten in relation1 eingefügt.



    Zitat Zitat von eazy
    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.
    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

  6. #6
    eazy ist offline Neuer Benutzer
    Registriert seit
    29.06.2006
    Ort
    Braunschweig
    Beiträge
    19

    Standard

    Zitat Zitat von fristo
    Vergess den Code und verwende den beschriebenen Trigger. Es geht einfacher: Lege den PK auf "name". Wenn Du dann folgenden Code ausführst

    Code:
    BEGIN;
    INSERT INTO relation1 (name) VALUES (xxxx);
    COMMIT;
    erhälst Du eine Fehlermeldung, falls xxxx schon in relation1 vorhanden ist, anderenfalls werden die neuen Daten in relation1 eingefügt.
    Wenn ich den Primary Key auf den Namen hätte legen können, hätte ich das schon gemacht. Leider geht das aber nicht, da in der Tabelle (die ich ja nur auszugsweise dargestellt habe) noch mehr Attribute gespeichert werden und der Name leider kein eindeutiges Attribut ist.

    Zitat Zitat von fristo
    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.
    Die Konsistenz hat definitiv höchste Priorität. Das Einfügen von 20.000 Tupeln erfolgt unter Umständen mehrmals täglich (weswegen diese Situation für mich momentan auch den höchsten Optimierungsbedarf hat). Der COPY Befehl ist, fürchte ich, für meine Zwecke leider zu unflexibel.

    Ich werde mich in der nächsten Woche mal dran setzen und einige Tests, was die Geschwindigkeit der einzelnen Vorschläge angeht, machen. Vielen Dank schon mal für die Hilfe! :-) Für heute ist jedoch erstmal Schluß mit Postgres...

    Gruß, eazy

  7. #7
    congor ist offline Neuer Benutzer
    Registriert seit
    30.03.2006
    Beiträge
    15

    Standard

    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

Ähnliche Themen

  1. Problem Datum in Tabelle einfügen
    Von AndreasBeginner im Forum SQL
    Antworten: 10
    Letzter Beitrag: 18.03.2009, 19:11
  2. Primary Key nachträglich einfügen
    Von g06lepe im Forum SQL
    Antworten: 3
    Letzter Beitrag: 26.02.2009, 16:51
  3. Daten in Tabelle einfügen
    Von buzz_lightzyear im Forum PGAdmin
    Antworten: 6
    Letzter Beitrag: 21.09.2008, 22:52
  4. Einfügen von Daten mit pgAdmin
    Von jogibear9988 im Forum Allgemeines
    Antworten: 2
    Letzter Beitrag: 29.02.2008, 13:30
  5. SQLDump in DB einfügen (mittels PHP)
    Von basti123456 im Forum SQL
    Antworten: 1
    Letzter Beitrag: 12.05.2006, 08:35

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Links: Tobias Bauer - IT- und Funkdienstleistungen   -   Bilderrahmen-kaufen.de - Der Onlineshop für Bilderrahmen & Fotorahmen   -   Funkforum