CẬP NHẬT
Câu trả lời này đã được kể từ thay thế với bài viết này: Data Imports, đại diện cho cách tiếp cận up-to-date nhất.
Để sao chép kịch bản của bạn tôi đã sử dụng pg-promise thư viện, và tôi có thể xác nhận rằng cố gắng nó đầu-on sẽ không bao giờ làm việc, cho dù thư viện bạn sử dụng, nó là cách tiếp cận những vấn đề.
Dưới đây là một phương pháp biến đổi mà chúng tôi phân vùng chèn vào khối và sau đó thực hiện từng đoạn trong một giao dịch, mà là cân bằng tải (aka throttling):
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();
});
này được sản xuất 1000.000 hồ sơ trong khoảng 4 phút, làm chậm đáng kể sau 3 giao dịch đầu tiên. Tôi đã sử dụng Node JS 0.10.38 (64 bit), tiêu thụ khoảng 340MB bộ nhớ. Bằng cách này, chúng tôi đã chèn 100.000 bản ghi, 10 lần liên tiếp.
Nếu chúng ta làm như vậy, chỉ lần này chèn 10.000 bản ghi trong 100 giao dịch, cùng 1.000.000 bản ghi được thêm vào chỉ trong 1m25, không chậm lại, với Node JS tiêu thụ khoảng 100MB bộ nhớ, cho chúng ta biết rằng phân vùng dữ liệu như Đây là một ý tưởng rất tốt.
Nó không quan trọng mà thư viện bạn sử dụng, phương pháp này nên được như vậy:
- Partition/ga chèn của bạn thành nhiều giao dịch;
- Giữ danh sách các lần chèn trong một giao dịch duy nhất với khoảng 10.000 hồ sơ;
- Thực hiện tất cả các giao dịch của bạn trong một chuỗi đồng bộ.
- Kết nối bản phát hành trở lại hồ bơi sau mỗi COMMIT của giao dịch.
Nếu bạn vi phạm bất kỳ quy tắc nào trong số đó, bạn sẽ được đảm bảo gặp sự cố. Ví dụ, nếu bạn phá vỡ quy tắc 3, quá trình Node JS của bạn có khả năng chạy hết bộ nhớ thật nhanh và đưa ra một lỗi. Quy tắc 4 trong ví dụ của tôi được cung cấp bởi thư viện.
Và nếu bạn làm theo mẫu này, bạn không cần phải gặp rắc rối với cài đặt nhóm kết nối.
UPDATE 1
phiên bản sau của pg-promise hỗ trợ các tình huống như vậy hoàn hảo, như hình dưới đây:
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);
});
và nếu bạn không muốn để bao gồm bất cứ điều gì thêm, như tạo bảng, sau đó nó trông thậm chí đơn giản hơn:
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;
});
Xem Synchronous Transactions để biết chi tiết.
Sử dụng thư viện hứa hẹn, ví dụ: phải mất 1m43s trên máy sản xuất của tôi để chèn 1.000.000 bản ghi (không có dấu vết ngăn xếp dài được bật).
Bạn sẽ chỉ có các yêu cầu trả lại phương thức factory
theo index
, cho đến khi bạn không còn gì, đơn giản như vậy.
Và phần tốt nhất, điều này không chỉ nhanh, mà còn tạo ra rất ít tải trên quy trình NodeJS của bạn. Quá trình kiểm tra bộ nhớ vẫn dưới 60MB trong toàn bộ thử nghiệm, chỉ tốn 7-8% thời gian CPU.
CẬP NHẬT 2
Bắt đầu với phiên bản 1.7.2, pg-promise hỗ trợ giao dịch siêu lớn một cách dễ dàng. Xem chương Synchronous Transactions.
Ví dụ: tôi có thể chèn 10.000.000 bản ghi trong một giao dịch duy nhất chỉ trong 15 phút trên máy tính ở nhà, với Windows 8.1 64 bit.
Để kiểm tra, tôi đặt PC ở chế độ sản xuất và sử dụng Bluebird làm thư viện lời hứa. Trong quá trình thử nghiệm, mức tiêu thụ bộ nhớ không vượt quá 75MB cho toàn bộ quá trình NodeJS 0.12.5 (64-bit), trong khi i7-4770 CPU của tôi cho thấy tải 15% phù hợp.
Chèn bản ghi 100 triệu theo cùng một cách sẽ đòi hỏi sự kiên nhẫn hơn, nhưng không cần nhiều tài nguyên máy tính hơn.
Trong thời gian chờ đợi, thử nghiệm trước đó cho chèn 1 m giảm từ 1m43 xuống còn 1m31.
CẬP NHẬT 3
Các yếu tố sau có thể làm cho một sự khác biệt rất lớn: Performance Boost.
CẬP NHẬT 4
câu hỏi liên quan, với một ví dụ thực hiện tốt hơn: Massive inserts with pg-promise.
CẬP NHẬT 5
Một ví dụ tốt hơn và mới hơn có thể được tìm thấy ở đây: nodeJS inserting Data into PostgreSQL error
Cảm ơn. Tôi đồng ý rằng đạo đức của câu chuyện là "đừng làm theo cách đó". FWIW Tôi đã kết thúc bằng cách sử dụng postgres COPY FROM. –
am i phải giả định rằng 'this.sequence (factory), this.one ('select count (*) from test')' sẽ không cung cấp cho tôi số đếm chính xác vì tôi không chắc chắn chuỗi được viết hoàn toàn khi bắt đầu truy vấn đếm? – stephanlindauer
@stephanlindauer khi trình tự giải quyết, nó giải quyết với một đối tượng '{total, duration}', do đó, tổng số là số lượng các phần tử được xử lý. –