我想处理10,000,000行
这是我的代码:
stmt.each('select * from very_big_table',function(err,rows,next){
console.log('This can take 2 seconds'
})
问题是:它会占用我所有的RAM,还是会从硬盘驱动器中读取一行?
答案 0 :(得分:0)
两者。如果函数是快速且同步的,statement.each
将不会使用任何额外的内存,但是对于异步函数,它将以从磁盘加载数据的速度开始所有异步处理,这将耗尽所有RAM。 / p>
正如您在https://github.com/mapbox/node-sqlite3/issues/686发布的问题中所述,您可以使用Statement.get()
获得所需的行为。没有任何参数的Statement.get()
将获取下一行。所以你可以像这样实现你自己的异步版本:
function asyncEach(db, sql, parameters, eachCb, doneCb) {
let stmt;
let cleanupAndDone = err => {
stmt.finalize(doneCb.bind(null, err));
};
stmt = db.prepare(sql, parameters, err => {
if (err) {
return cleanupAndDone(err);
}
let next = err => {
if (err) {
return cleanupAndDone(err);
}
return stmt.get(recursiveGet);
};
// Setup recursion
let recursiveGet = (err, row) => {
if (err) {
return cleanupAndDone(err);
}
if (!row) {
return cleanupAndDone(null);
}
// Call the each callback which must invoke the next callback
return eachCb(row, next);
}
// Start recursion
stmt.get(recursiveGet);
});
}

注意,语法与内置Statement.each
略有不同,错误仅发送到最后一个回调,不支持可选参数。
另请注意,这比普通的Statement.each
函数慢,可以通过发出多个get
调用来改进,以便下一行在调用next
时等待,但它是更难以遵循该代码。
使用代码段的示例:
let rowCount = 0;
asyncEach(db, 'SELECT * from testtable', [], (row, next) => {
assert.isObject(row);
rowCount++;
return next();
}, err => {
if (err) {
return done(err);
}
assert.equal(rowCount, TEST_ROW_COUNT);
done();
});