AKTUALIZUJ
Ta odpowiedź została zastąpiona tym artykułem:Import danych , który reprezentuje najbardziej aktualne podejście.
Aby odtworzyć Twój scenariusz, użyłem pg-promise i mogę potwierdzić, że próba bezpośredniego nigdy nie zadziała, bez względu na to, z której biblioteki korzystasz, to podejście ma znaczenie.
Poniżej znajduje się zmodyfikowane podejście, w którym dzielimy partycje na porcje, a następnie wykonujemy każdą porcję w ramach transakcji, co jest równoważeniem obciążenia (aka ograniczaniem):
function insertRecords(N) {
return db.tx(function (ctx) {
var queries = [];
for (var i = 1; i <= N; i++) {
queries.push(ctx.none('insert into test(name) values($1)', 'name-' + i));
}
return promise.all(queries);
});
}
function insertAll(idx) {
if (!idx) {
idx = 0;
}
return insertRecords(100000)
.then(function () {
if (idx >= 9) {
return promise.resolve('SUCCESS');
} else {
return insertAll(++idx);
}
}, function (reason) {
return promise.reject(reason);
});
}
insertAll()
.then(function (data) {
console.log(data);
}, function (reason) {
console.log(reason);
})
.done(function () {
pgp.end();
});
To dało 100 000 rekordów w około 4 minuty, drastycznie spowalniając po pierwszych 3 transakcjach. Używałem Node JS 0.10.38 (64-bit), który zużywał około 340MB pamięci. W ten sposób wstawiliśmy 100 000 rekordów, 10 razy z rzędu.
Jeśli zrobimy to samo, tylko tym razem wstawimy 10 000 rekordów w ramach 100 transakcji, te same 1 000 000 rekordów zostanie dodanych w zaledwie 1m25s, bez spowalniania, z Node JS zużywającym około 100 MB pamięci, co mówi nam, że takie partycjonowanie danych jest bardzo dobry pomysł.
Nie ma znaczenia, której biblioteki używasz, podejście powinno być takie samo:
- Podziel/ogranicz swoje wstawki do wielu transakcji;
- Utrzymuj listę wstawek w jednej transakcji na około 10 000 rekordów;
- Wykonaj wszystkie transakcje w łańcuchu synchronicznym.
- Zwolnij połączenie z powrotem do puli po każdej transakcji COMMIT.
Jeśli złamiesz którąkolwiek z tych zasad, masz gwarancję kłopotów. Na przykład, jeśli złamiesz regułę 3, twój proces Node JS prawdopodobnie bardzo szybko zabraknie pamięci i zgłosi błąd. Zasada 4 w moim przykładzie została dostarczona przez bibliotekę.
A jeśli zastosujesz się do tego wzorca, nie musisz zawracać sobie głowy ustawieniami puli połączeń.
AKTUALIZACJA 1
Późniejsze wersje pg-promise doskonale obsługują takie scenariusze, jak pokazano poniżej:
function factory(index) {
if (index < 1000000) {
return this.query('insert into test(name) values($1)', 'name-' + index);
}
}
db.tx(function () {
return this.batch([
this.none('drop table if exists test'),
this.none('create table test(id serial, name text)'),
this.sequence(factory), // key method
this.one('select count(*) from test')
]);
})
.then(function (data) {
console.log("COUNT:", data[3].count);
})
.catch(function (error) {
console.log("ERROR:", error);
});
a jeśli nie chcesz dodawać niczego dodatkowego, na przykład tworzenia tabel, wygląda to jeszcze prościej:
function factory(index) {
if (index < 1000000) {
return this.query('insert into test(name) values($1)', 'name-' + index);
}
}
db.tx(function () {
return this.sequence(factory);
})
.then(function (data) {
// success;
})
.catch(function (error) {
// error;
});
Zobacz Transakcje synchroniczne dla szczegółów.
Korzystanie z Bluebird
na przykład jako biblioteka obietnicy, na mojej maszynie produkcyjnej potrzeba 1m43s, aby wstawić 1 000 000 rekordów (bez włączonych długich śladów stosu).
Po prostu miałbyś swoją factory
metody zwracają żądania zgodnie z index
, dopóki nie zostanie ci nic, tak proste.
A najlepsze jest to, że jest to nie tylko szybkie, ale także w niewielkim stopniu obciąża proces NodeJS. Proces testowania pamięci pozostaje poniżej 60 MB podczas całego testu, zużywając tylko 7-8% czasu procesora.
AKTUALIZACJA 2
Począwszy od wersji 1.7.2, pg-promise z łatwością obsługuje supermasywne transakcje. Zobacz rozdział Transakcje synchroniczne .
Na przykład mogę wstawić 10 000 000 rekordów w jednej transakcji w zaledwie 15 minut na moim domowym komputerze z 64-bitowym systemem Windows 8.1.
Do testu ustawiłem komputer w trybie produkcyjnym i użyłem Bluebird jako biblioteka obietnic. Podczas testu zużycie pamięci nie przekroczyło 75 MB dla całego procesu NodeJS 0.12.5 (64-bitowego), podczas gdy mój procesor i7-4770 wykazywał stałe 15% obciążenie.
Wstawienie 100-metrowych rekordów w ten sam sposób wymagałoby tylko więcej cierpliwości, ale nie więcej zasobów komputerowych.
W międzyczasie poprzedni test dla 1m wstawek spadł z 1m43s do 1m31s.
AKTUALIZACJA 3
Następujące kwestie mogą mieć ogromne znaczenie:Wzrost wydajności .
AKTUALIZACJA 4
Powiązane pytanie, z lepszym przykładem implementacji:Masywne wstawki z pg-promise .
AKTUALIZACJA 5
Lepszy i nowszy przykład można znaleźć tutaj:nodeJS wstawianie danych w błąd PostgreSQL