0

10,000,000 行を処理したい

これは私のコードです:

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

問題は、RAM をすべて使い果たしてしまうのか、それともハード ドライブから行ごとに読み取るのかということです。

4

2 に答える 2

0

両方。statement.each関数が高速で同期している場合は余分なメモリを使用しませんが、非同期関数を使用すると、ディスクからデータをロードできるのと同じ速さですべての非同期処理が開始され、RAM がすべて消費されます。

ここに投稿した問題でも言われているように、 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();
});

于 2016-11-05T21:53:33.637 に答える