sql >> Database teknologi >  >> RDS >> PostgreSQL

node-postgres med enorme mængder af forespørgsler

OPDATERING

Dette svar er siden blevet afløst af denne artikel:Dataimport , som repræsenterer den mest opdaterede tilgang.

For at replikere dit scenarie brugte jeg pg-promise bibliotek, og jeg kan bekræfte, at det aldrig vil fungere at prøve det direkte, uanset hvilket bibliotek du bruger, det er tilgangen, der betyder noget.

Nedenfor er en modificeret tilgang, hvor vi opdeler indsættelser i chunks og derefter udfører hver chunk i en transaktion, som er load balancing (også kendt som throttling):

function insertRecords(N) { return db.tx(function (ctx) { var queries =[]; for (var i =1; i <=N; i++) { queries.push(ctx.none) ('indsæt i test(navn) værdier($1)', 'navn-' + i)); } returner løfte.alle(forespørgsler); });}funktion insertAll(idx) { if (!idx) { idx =0; } returner insertRecords(100000) .then(function () { if (idx>=9) { return promise.resolve('SUCCESS'); } else { return insertAll(++idx); } }, function (reason) { returner løfte.afvis(årsag); });}indsætAlle() .then(funktion (data) { console.log(data); }, funktion (årsag) { console.log(årsag); }) .done(funktion () { pgp.end(); }); 

Dette producerede 1.000.000 poster på omkring 4 minutter, hvilket faldt dramatisk efter de første 3 transaktioner. Jeg brugte Node JS 0.10.38 (64-bit), som forbrugte omkring 340 MB hukommelse. På denne måde indsatte vi 100.000 poster, 10 gange i træk.

Hvis vi gør det samme, indsætter kun denne gang 10.000 poster inden for 100 transaktioner, de samme 1.000.000 poster tilføjes på kun 1m25s, ingen sænkning, med Node JS, der bruger omkring 100 MB hukommelse, hvilket fortæller os, at partitionering af data som denne er en meget god idé.

Det er lige meget hvilket bibliotek du bruger, fremgangsmåden bør være den samme:

  1. Partitioner/spær dine skær i flere transaktioner;
  2. Behold listen over indstik i en enkelt transaktion på omkring 10.000 poster;
  3. Udfør alle dine transaktioner i en synkron kæde.
  4. Slå forbindelsen tilbage til puljen efter hver transaktions COMMIT.

Hvis du bryder nogen af ​​disse regler, er du garanteret problemer. For eksempel, hvis du bryder regel 3, vil din Node JS-proces sandsynligvis løbe tør for hukommelse meget hurtigt og give en fejl. Regel 4 i mit eksempel blev leveret af biblioteket.

Og hvis du følger dette mønster, behøver du ikke besvære dig selv med indstillingerne for forbindelsespuljen.

OPDATERING 1

Senere versioner af pg-promise understøtter sådanne scenarier perfekt, som vist nedenfor:

funktion fabrik(indeks) { if (indeks <1000000) { return this.query('insert into test(name) values($1)', 'name-' + index); }}db.tx(function () { return this.batch([ this.none('slip tabel, hvis der findes test'), this.none('create table test(id serial, name text)'), this.sequence (fabrik), // nøglemetode this.one('vælg antal(*) fra test') ]);}) .then(funktion (data) { console.log("COUNT:", data[3].count ); }) .catch(funktion (fejl) { console.log("FEJL:", fejl); });

og hvis du ikke ønsker at inkludere noget ekstra, såsom oprettelse af bord, så ser det endnu enklere ud:

funktion fabrik(indeks) { if (indeks <1000000) { return this.query('insert into test(name) values($1)', 'name-' + index); }}db.tx(function () { return this.sequence(factory);}) .then(funktion (data) { // succes; }) .catch(funktion (fejl) { // fejl; });

Se Synkrone transaktioner for detaljer.

Brug af Bluebird som løftebiblioteket, for eksempel, tager det 1m43s på min produktionsmaskine at indsætte 1.000.000 poster (uden lange stakspor aktiveret).

Du ville bare have din fabrik metode returnerer anmodninger i henhold til indekset , indtil du ikke har nogen tilbage, så simpelt er det.

Og det bedste er, at dette ikke bare er hurtigt, men også en lille belastning på din NodeJS-proces. Hukommelsestestprocessen forbliver under 60 MB under hele testen og bruger kun 7-8 % af CPU-tiden.

OPDATERING 2

Startende med version 1.7.2, pg-promise understøtter super-massive transaktioner med lethed. Se kapitlet Synkrone transaktioner .

For eksempel kunne jeg indsætte 10.000.000 poster i en enkelt transaktion på kun 15 minutter på min hjemme-pc med Windows 8.1 64-bit.

Til testen satte jeg min pc til produktionstilstand og brugte Bluebird som løftebiblioteket. Under testen gik hukommelsesforbruget ikke over 75 MB for hele NodeJS 0.12.5-processen (64-bit), mens min i7-4770 CPU viste en konstant belastning på 15 %.

At indsætte 100 mio. poster på samme måde ville kræve bare mere tålmodighed, men ikke flere computerressourcer.

I mellemtiden faldt den tidligere test for 1m skær fra 1m43s til 1m31s.

OPDATERING 3

Følgende overvejelser kan gøre en kæmpe forskel:Performance Boost .

OPDATERING 4

Relateret spørgsmål med et eksempel på en bedre implementering:Massive indsatser med pg-promise .

OPDATERING 5

Et bedre og nyere eksempel kan findes her:nodeJS inserting Data ind i PostgreSQL-fejl



  1. Sådan får du server OS lokal tid i alle Postgres-versioner

  2. Forsøger at bygge en statisk databaseklasse, som jeg kan få adgang til fra enhver funktion uden for klassen

  3. HQL / JPA finde tilgængelige varer mellem datointerval

  4. Hvordan laver man en masseindsættelse i MySQL?