在Node.js中使用mysql模块处理大型数据表

4
我有一个包含大约1000万行的MySQL数据库中的大型表格,需要将这些数据转换成JSON格式。对于较小的表格,我会使用基本的connection.query("SELECT * FROM TABLE, function(err, results) {});语法。但是,我不想将整个表格加载到内存中。
我注意到mysql模块具有“流式”行的功能(https://github.com/felixge/node-mysql/#streaming-query-rows),因此我想知道它是否仍会将整个表格加载到内存中,然后逐一提供每一行,或者实际上只加载一行,因此整个表格从未完全存储在内存中。
3个回答

3

分块加载数据。以下是一些可行的示例。

var mysql = require('mysql');
var settings = {};

settings.host = "localhost";
settings.user = "root";
settings.password = "root";
settings.database = "dbname";

var pool = mysql.createPool(settings);

var countQuery = "SELECT count(*) as total FROM tbl";

var chunkSize = 1000;

pool.getConnection(function(err, connection) {
    if (err) {
        connection.release();
        console.log("Error on getConnection:", err);
        return;
    }

    connection.query(countQuery, {}, function(err, result) {
        if (err) {
            connection.release();
            console.log("Error on getConnection:", err);
            return;
        }

        if (result && result[0]) {
            var totalRows = result[0]['total'];
            console.log("Total rows in db:", totalRows);
            var periods = Math.ceil(totalRows/chunkSize)
            console.log("Total periods", periods);

            var selectQuery = "SELECT * FROM tbl ORDER BY id DESC LIMIT ";

            for(var i = 0; i < periods; i++) {
                var offset = i*chunkSize;

                var runQuery = selectQuery + offset + "," + chunkSize;

                console.log(runQuery);

                connection.query(runQuery, {}, function (err, results) {
                    if (err) {
                        console.log("Error on runQuery:", err);
                        return;
                    }

                    console.log("Data:", results);
                });
            }

            connection.release();
        }
    });
});

1
这种方法可能会导致错误的数据传输,因为它被分成几个不同的SQL语句,在不同的时间进行查询,并且没有对表进行写锁定。 - Lilleman
你是对的。更好的方法是使用递归或者一些循环对象。但是思路是相同的。 - Alexander R.
嗯,我很想把这个问题转交给数据库引擎的设计师。我认为他们已经对这个问题进行了长时间的思考。因此,我希望我的应用程序能够从数据库中流式传输数据,而不是将其作为块下载。正如最初的问题所提到的那样,https://github.com/felixge/node-mysql/#streaming-query-rows 似乎可以做到这一点。我在一个有4000万行的表上尝试了一下,它在我的节点应用程序上具有低内存消耗,并且运行良好。 - Lilleman
@Lilleman 我正在构建一个 Node 应用程序,将 Oracle 数据带到 Mysql。我担心如何处理大量数据(例如:1000k)。我的第一种方法是将数据保存为 CSV,使用 Oracle SQLPlus 命令行保存 CSV 文件,然后使用 Mysql 命令行导入它。我想知道你的流式传输方法是否更好。你能给我一些提示吗?将大数据传输到另一个表的最佳方式是什么(Oracle => Mysql 或 Mysql => Mysql)? - calebeaires
@calebeaires 我对Oracle几乎一无所知,但如果要将数据从MySQL移动到MySQL,我会使用shell工具。类似这样:mysqldump -h source_host -u root -p --hex-blob source_db_name table_name | mysql -h target_host -u root -p target_db_name当从CSV导入时,如果您想更改数据,则还可以通过节点流传输CSV。我正在使用fast-csv模块进行操作,效果非常好。请注意,您必须暂停CSV流并允许数据库赶上,否则您将耗尽内存,因为CSV流比数据库写入速度快得多。 - Lilleman

0

虽然回答有些晚,但对于需要在2021年使用优化的时间更少的解决方案的人

上述所有解决方案都不错,但存在以下问题

  1. 时间复杂度为O(n)
  2. 高存储复杂度为O(n)或高内存使用问题,有时应用程序可能会因请求过多而崩溃

解决方案:在用户执行CRUD操作(例如put请求)时维护同步的JSON文件。

app.put('/product/:id', (res,req)=>{
    // step 1 do update operation in db
    // step 2 do update operation in JSON file

    return res.send('OK 200')

})

所以下一次当用户请求JSON时,用户可以立即获得JSON文件

愉快的编码 :)


0
我脑海中首先浮现出的是动态分页。我相信你对MySQL的偏移和限制很熟悉,通过它可以控制查询。
  1. 第一次查询,获取1000行。
  2. 如果成功,再添加查询下一个1000行。
  3. 递归地继续这个过程。

但是正如评论反对其他答案所说,确保你写锁定表格,否则可能会得到意外的结果。 - Lee Goddard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接