`node-sqlite每个函数都将所有查询加载到内存中,或者它使用来自硬盘的流/管道

时间:2016-08-10 09:28:01

标签: node.js node-sqlite3

我想处理10,000,000行

这是我的代码:

stmt.each('select * from very_big_table',function(err,rows,next){
      console.log('This can take 2 seconds'
})

问题是:它会占用我所有的RAM,还是会从硬盘驱动器中读取一行?

1 个答案:

答案 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();
});