如何使用Node.js异步查询大量数据?

时间:2016-12-23 12:31:12

标签: javascript mysql node.js asynchronous

我正在尝试从mysql数据库中查询400k行,一次获取10个。要异步执行此操作,我需要使用这样的递归:

var migrate = function(offset, size) {
  Mysql.query(query, [offset, size], function(err, rows) {
    if (!err && rows.length) {
      setTimeout(function() {
        // Pretend doing something and get next batch.
        migrate(offset + size, size);
      }, 1000);
    }
  });
};

migrate(0, 10);

问题是,migrate()的第一次调用会创建一个自己的子回调,并且所有这些回调都会留在内存中,直到最后migrate()完成。

想到的唯一解决方案是在while循环中同步运行它。

请告知您如何正确地做到这一点?感谢。

2 个答案:

答案 0 :(得分:0)

在使用mysql模块的当前示例中,可以通过查询所有记录而不进行分块并使用Streaming query rows来完成。一旦处理完结果,它将逐个运行查询。

Mysql.query(sql).on('result', function(row) {
  Mysql.pause();
  setTimeout(function() {
    // Pretend doing something.
    Mysql.resume();
  }, 1000);
});

但是(!),result回调不应该有任何闭包变量,因为在这种情况下这些变量将保留内存。我做了一些基准测试,这是我对它的了解,否则无法解释。

一般来说,如果你需要处理大量数据,无论是mysql还是其他什么都没关系,我建议:

  1. 使用streams
  2. 使用process.nextTick()
  3. 不要使用封闭装置。
  4. 不要使用递归。

答案 1 :(得分:0)

看看SynJS - 它允许同步运行javascript代码:

var SynJS = require('synjs');
var mysql      = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'tracker',
  password : 'tracker123',
  database : 'tracker'
});


function myMigrate(modules,connection) {
    for(var i=0; i<4; i++) {
        connection.query("SELECT CONCAT('processing data batch #',?) as res",[i], function(err, rows, fields) {
              if (err) throw err;
              console.log(i,rows[0].res);
              modules.SynJS.resume(_synjsContext);
        });
        SynJS.wait();
    }
};

var modules = {
        SynJS:  SynJS,
        mysql:  mysql,
};

SynJS.run(myMigrate,null,modules,connection,function () {
    console.log('done');
});

结果将是:

0 'processing data batch #0'
1 'processing data batch #1'
2 'processing data batch #2'
3 'processing data batch #3'
done