我尝试使用 knex.js 将整个sqlite3数据库表导出为CSV。由于表格最多可达300000行,因此我使用流来解决内存问题。但是,如果我看看我的应用程序的内存使用量高达800MB,或者我有一个"内存不足"错误。
如何在sqlite3数据库上使用knex.js处理大型查询结果?
以下代码示例:
knex.select().from(table).stream(function (stream) {
var stringifier = stringify(opts);
var fileStream = fs.createWriteStream(file);
var i = 0;
stringifier.on('readable', function() {
var row;
while (row = stringifier.read()) {
fileStream.write(row);
console.log("row " + i++); //debug
}
});
fileStream.once('open', function(fd) {
stream.pipe(stringifier);
});
});
修改
似乎sqlite3数据库的knex.js流是"假的"流。 下面是knex中sqlite3的流函数的源代码:
Runner_SQLite3.prototype._stream = Promise.method(function(sql, stream, options) {
/*jshint unused: false*/
var runner = this;
return new Promise(function(resolver, rejecter) {
stream.on('error', rejecter);
stream.on('end', resolver);
return runner.query(sql).map(function(row) {
stream.write(row);
}).catch(function(err) {
stream.emit('error', err);
}).then(function() {
stream.end();
});
});
});
我们看到它在创建流之前等待执行请求 来自结果数组。
版本:
感谢您的帮助。
答案 0 :(得分:5)
我认为没有解决方案。我使用limit和offset来逐步使用knex.js获取所有数据,并在写入流中写入每一行。 想要的人的实现示例:
exportTable: function(table, writeStream) {
var totalRows;
var rowLimit = _config.ROW_LIMIT;
return DatabaseManager.countAll(table).then(function(count) {
totalRows = count[0]['count(*)'];
var iterations = new Array(Math.ceil(totalRows / rowLimit));
return Promise.reduce(iterations, function(total, item, index) {
return _knex.select().from(table).limit(rowLimit).offset(index * rowLimit).map(function(row) {
writeStream.write(row);
}).catch(function(err) {
return Promise.reject(err);
});
}, 0).then(function() {
return Promise.resolve();
}).catch(function(err) {
return Promise.reject(err);
});
}).catch(function(err) {
console.log(err);
return Promise.reject(err);
});
}