2016-08-07 10 views
2

Ich versuche, über 1 Million Zeilen in Postgres Tabelle mit NodeJs einfügen Das Problem ist, wenn ich Skript beginne, der Speicher ständig zu erhöhen, bis es 1,5 GB RAM erreichen und I-Fehler dann erhalten: FATAL eRROR: CALL_AND_RETRY_LAST Allocation fehlgeschlagen - Prozess aus dem SpeicherFügen Sie eine große Anzahl von Zeilen in Postgres DB mit NodeJS

das Ergebnis ist immer das gleiche - etwa 7000 eingefügten Zeilen anstelle von 1 Million

Hier ist der Code

var pg = require('pg'); 
var fs = require('fs'); 
var config = require('./config.js'); 



var PgClient = new pg.Client(config.pg); 
PgClient.connect(); 

var lineReader = require('readline').createInterface({ 
     input: require('fs').createReadStream('resources/database.csv') //file contains over 1 million lines 
    }); 
var n=0; 




lineReader.on('line', function(line) { 
     n++; 
     var insert={"firstname":"John","lastname":"Conor"}; 

     //No matter what data we insert, the point is that the number of inserted rows much less than it should be 
     PgClient.query('INSERT INTO HUMANS (firstname,lastname) values ($1,$2)', [insert.firstname,insert.lastname]); 

}); 

lineReader.on('close',function() { 
    console.log('end '+n); 
}); 
+0

Haben Sie versucht zu pausieren, sobald Sie eine Zeile erhalten und wieder aufnehmen, sobald der Rückruf der Abfrage aufgerufen wurde? Ich denke, es sind zu viele Anfragen in der Warteschlange, und das könnte Ihren Prozessspeicher erschöpfen. – mscdex

+0

I aded lineReader.pause(); vor Abfrage und lineReader.resume(); Nach der Abfrage sieht das aber nicht so aus. Derselbe Fehler – m3n1at

+2

Ziehen Sie stattdessen Masseneinfügungen in Betracht. Das Einfügen auf einer Zeile ist zu teuer. –

Antwort

-1

Also habe ich das Problem gelöst. Es gibt PgClient.queryQueue, das mit viel weniger Geschwindigkeit als das Lesen der Datei verarbeitet wird. Und wenn eine große Datei gelesen wird, ist die Warteschlange übergelaufen. Und hier die Lösung, sollten wir lineReader.on (‚line‘, cb) Abschnitt ändern, jedes Mal, wenn die Warteschlange viele Elemente hat man lineReader

lineReader.on('line', function(line) { 
     n++; 
     var insert={"firstname":"John","lastname":"Conor"}; 
     PgClient.query('INSERT INTO HUMANS (firstname,lastname) values ($1,$2)', [insert.firstname,insert.lastname],function (err,result){ 
      if (err) console.log(err); 
      if (PgClient.queryQueue.length>15000) { 
       lineReader.pause(); 
      } 
      else lineReader.resume(); 
     }); 
}); 
+0

Dies ist eine schlechte Lösung, während die richtige trivial ist - lesen Sie Zeilen aus der Datei in Stapeln von etwa 1000-10.000 Einfügungen, und fügen Sie jeden solchen Lesevorgang als Stapel ein. Außerdem müssen Sie Einfügungen verketten - siehe [Performance Boost] (https://github.com/vitaly-t/pg-promise/wiki/Performance-Boost). –

1

habe ich pg-Versprechen Pause als vitaly-t vorgeschlagen . Und dieser Code funktioniert wirklich schnell

const fs = require('fs'); 
const pgp = require('pg-promise')(); 
const config = require('./config.js'); 

// Db connection 
const db = pgp(config.pg); 

// Transform a lot of inserts into one 
function Inserts(template, data) { 
    if (!(this instanceof Inserts)) { 
     return new Inserts(template, data); 
    } 
    this._rawType = true; 
    this.toPostgres =() => { 
     return data.map(d => '(' + pgp.as.format(template, d) + ')').join(); 
    }; 
} 

// insert Template 
function Insert() { 
     return { 
      firstname: null, 
      lastname: null, 
      birthdate:  null, 
      phone: null, 
      email: null, 
      city: null, 
      district: null, 
      location: null, 
      street: null 
     }; 
}; 
const lineReader = require('readline').createInterface({ 
     input: require('fs').createReadStream('resources/database.csv') 
    }); 


let n = 0; 
const InsertArray = []; 

lineReader.on('line', function(line) { 
     var insert = new Insert(); 
     n ++; 
     var InsertValues=line.split(','); 
     if (InsertValues[0]!=='"Firstname"'){ //skip first line 
      let i = 0; 
      for (let prop in insert){ 
       insert[prop] = (InsertValues[i]=='')?insert[prop]:InsertValues[i]; 
       i++; 
      } 
      InsertArray.push(insert); 
      if (n == 10000){ 
       lineReader.pause(); 
       // convert insert array into one insert 
       const values = new Inserts('${firstname}, ${lastname},${birthdate},${phone},${email},${city},${district},${location},${street}', InsertArray); 
       db.none('INSERT INTO users (firstname, lastname,birthdate,phone,email,city,district,location,street) VALUES $1', values) 
       .then(data => { 
        n = 0; 
        InsertArray=[]; 
        lineReader.resume(); 
       }) 
       .catch(error => { 
        console.log(error); 
       }); 
      } 
     } 
}); 


lineReader.on('close',function() { 
    console.log('end '+n); 
    //last insert 
    if (n > 0) { 
     const values = new Inserts('${firstname}, ${lastname},${birthdate},${phone},${email},${city},${district},${location},${street}', InsertArray); 
     db.none('INSERT INTO users (firstname, lastname,birthdate,phone,email,city,district,location,street) VALUES $1', values) 
      .then(data => { 
       console.log('Last'); 
      }) 
      .catch(error => { 
       console.log(error); 
      }); 
    } 
}); 
+0

Bestes Beispiel: [Datenimport] (https://github.com/vitaly-t/pg-promise/wiki/Data-Imports). –

+0

Ich habe das Codebeispiel für die Einhaltung der neuesten Version von pg-promise v6.5.0 aktualisiert –