2017-01-22 5 views
2

Ich benutze pg-promise und ich möchte mehrere Einsätze zu einer Tabelle machen. Ich habe einige Lösungen wie Multi-row insert with pg-promise und How do I properly insert multiple rows into PG with node-postgres? gesehen, und ich könnte pgp.helpers.concat verwenden, um mehrere Auswahlmöglichkeiten zu verketten.Massive Einsätze mit pg-Versprechen

Aber jetzt, ich brauche eine Menge Messungen in einer Tabelle einzufügen, mit mehr als 10.000 Datensätzen und in https://github.com/vitaly-t/pg-promise/wiki/Performance-Boost sagt: „Wie viele Datensätze, die Sie wie folgt verketten kann - auf die Größe der Datensätze abhängt, sondern Ich würde mit diesem Ansatz niemals über 10.000 Datensätze gehen. Wenn Sie also viel mehr Datensätze einfügen müssen, möchten Sie sie in solche verketteten Stapel aufteilen und dann nacheinander ausführen. "

Ich lese den ganzen Artikel, aber ich kann nicht herausfinden, wie ich meine Einsätze in Chargen "splitte" und dann nacheinander ausführen soll.

Danke!

+0

Besser spät als nie, da ich endlich Zeit hatte, Ihre Frage erneut zu lesen und die richtige Antwort innerhalb der bestehenden [pg-promise] (https://github.com/vitaly-t/pg-promise) API zu geben ;) –

+0

Vielen Dank für Ihre Antwort @ vitaly-t, ich habe es implementiert und es funktioniert jetzt! Ich werde Ihre Antwort akzeptieren, weil ich denke, dass es eine bessere Implementierung ist, die Sequenz statt Batch verwendet. –

Antwort

1

UPDATE

Am besten ist es in dem folgenden Artikel zu lesen: Data Imports.


Als Autor pg-promise ich gezwungen war, endlich auf die Frage die richtige Antwort zu geben, wie die früher veröffentlichte eine wirklich Gerechtigkeit es nicht tun.

Um eine massive/unendliche Anzahl von Datensätzen einzufügen, sollte Ihr Ansatz auf der Methode sequence basieren, die in Tasks und Transaktionen verfügbar ist.

var cs = new pgp.helpers.ColumnSet(['col_a', 'col_b'], {table: 'tableName'}); 

// returns a promise with the next array of data objects, 
// while there is data, or an empty array when no more data left 
function getData(index) { 
    if (/*still have data for the index*/) { 
     // - resolve with the next array of data 
    } else { 
     // - resolve with an empty array, if no more data left 
     // - reject, if something went wrong 
    }   
} 

function source(index) { 
    var t = this; 
    return getData(index) 
     .then(data => { 
      if (data.length) { 
       // while there is still data, insert the next bunch: 
       var insert = pgp.helpers.insert(data, cs); 
       return t.none(insert); 
      } 
      // returning nothing/undefined ends the sequence 
     }); 
} 

db.tx(t => t.sequence(source)) 
    .then(data => { 
     // success 
    }) 
    .catch(error => { 
     // error 
    }); 

Dies ist der beste Ansatz zum Einfügen einer großen Anzahl von Zeilen in die Datenbank, sowohl vom Leistungspunkt als auch von der Lastdrosselung.

Alles, was Sie tun müssen, ist die Implementierung Ihrer Funktion getData entsprechend der Logik Ihrer App, dh wo Ihre großen Daten stammen, basierend auf der index der Sequenz, um einige 1.000 - 10.000 Objekte auf einmal zurückzugeben, abhängig von der Größe der Objekte und der Datenverfügbarkeit.

Siehe auch einige API Beispiele:


Verwandte Frage: node-postgres with massive amount of queries.


Und in Fällen, in denen Sie benötigen erzeugt id-s aller eingefügten Datensätze zu erwerben, können Sie die beiden Linien ändern würde, wie folgt:

// return t.none(insert); 
return t.map(insert + 'RETURNING id', [], a => +a.id); 

und

// db.tx(t => t.sequence(source)) 
db.tx(t => t.sequence(source, {track: true})) 

nur Seien Sie vorsichtig, wenn Sie zu viele Record-IDs im Speicher halten, kann dies zu einer Überlastung führen.

+0

Vielen Dank für Ihre Antwort! Schließlich habe ich Ihre Antwort implementiert und es funktioniert perfekt. Wenn meine Informationsfelder in einem Array gespeichert werden, könnte ich dann die getData-Funktion nicht aufrufen und bei gegebenem Index nur innerhalb der Quelle das nächste Array von Daten aus dem Haupt-Array zurückgeben? Ich dachte, etwas zu verwenden, wie es in der Dokumentation ist: 'Funktion Quelle (Index) { if (index

1

Ich denke, der naive Ansatz würde funktionieren.

Versuchen Sie, Ihre Daten in mehrere Teile von 10.000 Datensätze oder weniger aufzuteilen. Ich würde versuchen, das Array unter Verwendung der Lösung von diesem zu trennen.

Dann mehrere Zeilen einfügen jedes Array mit pg-promise und führen sie nacheinander in einer Transaktion.

Edit: Dank @ Vitaly-T für die wunderbare Bibliothek und zur Verbesserung meiner Antwort.

Vergessen Sie auch nicht, Ihre Abfragen in eine Transaktion zu wickeln, sonst wird die Verbindungen erschöpfen.

Um dies zu tun, verwenden Sie die batch Funktion von pg-Versprechen alle Abfragen asynchron zu beheben:

// split your array here to get splittedData 
int i = 0 
var cs = new pgp.helpers.ColumnSet(['col_a', 'col_b'], {table: 'tmp'}) 

// values = [..,[{col_a: 'a1', col_b: 'b1'}, {col_a: 'a2', col_b: 'b2'}]] 
let queries = [] 
for (var i = 0; i < splittedData.length; i++) { 
    var query = pgp.helpers.insert(splittedData[i], cs) 
    queries.push(query) 
} 

db.tx(function() { 
    this.batch(queries) 
}) 
.then(function (data) { 
    // all record inserted successfully ! 
} 
.catch(function (error) { 
    // error; 
}); 
+0

Ok, Danke für die Post! Ich habe es verstanden, aber ich visualisiere immer noch nicht die nextMultiRowInsert() - Funktion, sollte es eine rekursive Funktion für den Code sein, den Sie eingereicht haben, bis ich nicht mehr Daten habe? –

+1

Sie müssen es innerhalb einer Transaktion tun, sonst werden die Verbindungen aufgebraucht. –

+0

@ Vitaly-t guter Punkt. Ich werde meine Antwort bearbeiten – AlexB