CẬP NHẬT
Câu trả lời này đã được thay thế bằng bài viết này: Nhập dữ liệu , đại diện cho cách tiếp cận cập nhật nhất.
Để tái tạo 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 việc thử trực tiếp sẽ không bao giờ hiệu quả, bất kể bạn sử dụng thư viện nào, đó là cách tiếp cận quan trọng.
Dưới đây là một cách tiếp cận đã sửa đổi, trong đó chúng tôi phân vùng chèn thành các phần và sau đó thực thi từng phần trong một giao dịch, đó là cân bằng tải (hay còn gọi là điều chỉnh):
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();
});
Điều này đã tạo ra 1000.000 bản ghi trong khoảng 4 phút, chậm lại đáng kể sau 3 giao dịch đầu tiên. Tôi đang sử dụng Node JS 0.10.38 (64-bit), tiêu tốn khoảng 340 MB 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 tương tự, chỉ lần này chèn 10.000 bản ghi trong 100 giao dịch, 1.000.000 bản ghi tương tự được thêm vào chỉ trong 1 phút 25 giây, không làm chậm, với Node JS tiêu tốn khoảng 100MB bộ nhớ, điều này cho chúng ta biết rằng dữ liệu phân vùng như thế này là rất ý kiến hay.
Không quan trọng bạn sử dụng thư viện nào, cách tiếp cận phải giống nhau:
- Phân chia / điều chỉnh các khoản chèn của bạn vào nhiều giao dịch;
- Giữ danh sách các lần chèn trong một giao dịch duy nhất ở khoảng 10.000 bản ghi;
- Thực hiện tất cả các giao dịch của bạn trong một chuỗi đồng bộ.
- Giải phóng kết nối trở lại nhóm sau CAM KẾT của mỗi giao dịch.
Nếu bạn vi phạm bất kỳ quy tắc nào trong số đó, bạn chắc chắn sẽ gặp rắc rối. 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 hết bộ nhớ thực sự nhanh chóng và gây ra lỗi. Quy tắc 4 trong ví dụ của tôi do thư viện cung cấp.
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.
CẬP NHẬT 1
Các phiên bản sau của pg-promise hỗ trợ các tình huống như vậy một cách hoàn hảo, như được hiển thị bên dưới:
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 thêm bất cứ thứ gì, chẳng hạn như tạo bảng, thì nó trông còn đơ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 Giao dịch đồng bộ để biết chi tiết.
Sử dụng Bluebird
chẳng hạn như thư viện lời hứa, máy sản xuất của tôi mất 1 phút 43 giây để chèn 1.000.000 bản ghi (không bật dấu vết ngăn xếp dài).
Bạn sẽ chỉ có factory
của mình yêu cầu trả về phương thức 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 ít tải cho quy trình NodeJS của bạn. Quá trình kiểm tra bộ nhớ duy trì dưới 60MB trong toàn bộ quá trình kiểm tra, chỉ tiêu tốn 7-8% thời gian của CPU.
CẬP NHẬT 2
Bắt đầu với phiên bản 1.7.2, pg-promise hỗ trợ các giao dịch siêu lớn một cách dễ dàng. Xem chương Giao dịch đồng bộ .
Ví dụ:tôi có thể chèn 10.000.000 bản ghi trong một giao dịch chỉ trong 15 phút trên PC tại nhà, với Windows 8.1 64-bit.
Để kiểm tra, tôi đặt PC của mình ở chế độ sản xuất và sử dụng Bluebird như 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ộ quy trình NodeJS 0.12.5 (64-bit), trong khi CPU i7-4770 của tôi cho thấy mức tải ổn định 15%.
Chèn bản ghi 100m theo cách tương tự sẽ chỉ cần thêm sự kiên nhẫn chứ không cần nhiều tài nguyên máy tính hơn.
Trong khi đó, bài kiểm tra trước đó đối với lượt chèn 1m đã giảm từ 1m43s xuống còn 1m31s.
CẬP NHẬT 3
Những cân nhắc sau có thể tạo ra sự khác biệt lớn: Tăng hiệu suất .
CẬP NHẬT 4
Câu hỏi liên quan, với một ví dụ triển khai tốt hơn: Chèn hàng loạt với pg-promise .
CẬP NHẬT 5
Bạn có thể tìm thấy một ví dụ tốt hơn và mới hơn tại đây: chèn dữ liệu nodeJS gặp lỗi PostgreSQL