У меня есть скромный Node.js script, который извлекает данные из Википедии через API и сохраняет их в базе данных SQLite. Я использую этот node-sqlite3 модуль.
В некоторых случаях я собираю данные по 600 000 статей и храня некоторые метаданные о каждом из них в строке в db. Статьи извлекаются группами по 500 из API.
Запрос, который извлекает объект JSON с данными в 500 статьях, передает объект этому обратному вызову:
//(db already instantiated as 'new sqlite.Database("wikipedia.sqlite");')
function callback(articles) {
articles.forEach(function(article) {
db.run("INSERT OR IGNORE INTO articles (name, id, created) VALUES (?,?,?)", [article["title"], article["pageid"], article["timestamp"]]);
});
}
Модули работают по умолчанию параллельно, но документация для node -sqlite3 включает в себя один пример последовательных операций:
db.serialize(function() {
db.run("CREATE TABLE lorem (info TEXT)");
var stmt = db.prepare("INSERT INTO lorem VALUES (?)");
for (var i = 0; i < 10; i++) {
stmt.run("Ipsum " + i);
}
stmt.finalize();
}
Я попытался подражать этому и почти не видел разницы в производительности. Я делаю это неправильно? Прямо сейчас данные извлекаются из API намного быстрее, чем записываются в БД, хотя это не невыносимо медленно. Но избиение БД с помощью индивидуальных команд INSERT
с числами 600K кажется неуклюжим.
UPDATE: В соответствии с принятым ответом это работает для node -sqlite3, вместо собственного решения. (См. Issue).
db.run("BEGIN TRANSACTION");
function callback(articles) {
articles.forEach(function(article) {
db.run("INSERT OR IGNORE INTO articles (name, id, created) VALUES (?,?,?)", [article["title"], article["pageid"], article["timestamp"]]);
});
}
db.run("END");