【问题标题】:Using the mysql module in node.js for large tables将 node.js 中的 mysql 模块用于大型表
【发布时间】:2015-09-12 19:43:44
【问题描述】:

我的 MySQL 数据库中有一个大表(大约 1000 万行),我需要将所有这些数据转换为 JSON 格式。对于较小的表,我会使用基本的connection.query("SELECT * FROM TABLE, function(err, results) {}); 语法。但是,我不想将整个表加载到内存中。

我注意到 mysql 模块具有“流式传输”行的能力 (https://github.com/felixge/node-mysql/#streaming-query-rows),所以我想知道它是否仍将整个表加载到内存中,然后将每一行一一提供给我们,或者它是否真的一次只加载一行,所以整个表永远不会一次存储在内存中。

【问题讨论】:

    标签: mysql sql node.js stream streaming


    【解决方案1】:

    回答为时已晚,但对于 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文件

    编码愉快:)

    【讨论】:

      【解决方案2】:

      按块加载数据。这里有一些工作示例。

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

      【讨论】:

      • 这种方法可能会导致错误的数据被传输,因为它被分割成几个不同的 SQL 语句,在不同的时间被查询,而表上没有写锁。
      • 你是对的。更好的方法是使用递归或使用一些 lob。但想法是一样的。
      • 是的,我很想把这个问题交给数据库引擎的设计者。我想他们已经在这个问题上考虑了很久很久。因此,我希望我的应用程序从数据库流式传输数据,而不是将其作为块下载。 github.com/felixge/node-mysql/#streaming-query-rows 正如最初的问题中提到的那样,似乎就是这样做的。我在一个 40miljon 行的表上进行了尝试,它在我的节点应用程序上运行良好,内存消耗低。
      • @Lilleman 我正在构建一个将 Oracle 数据引入 Mysql 的节点应用程序。我担心会带来大量数据(例如:1000k)。我的第一种方法是将数据保存为 CSV,使用 Oracle SQLPlus 命令行保存 csv 文件,然后使用 Mysql 命令行导入它。我想知道您的流方法是否会更好。你能给我一个线索吗?将大数据传输到另一个表(Oracle => Mysql 或 Mysql => Mysql)的最佳方式是什么?
      • @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 流比数据库写入快得多。
      【解决方案3】:

      我首先想到的是动态分页。我相信你熟悉 mysql 的偏移量和限制,有了它,你可以控制你的查询。

      1. 第一次查询,得到 1000 行。
      2. 如果成功,则在接下来的 1000 行中再次添加查询。
      3. 递归执行。

      【讨论】:

      • 但正如 cmets 所说,反对其他答案,请确保您对表进行写锁定,否则您可能会得到意想不到的结果。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-30
      • 2013-08-10
      • 2021-08-21
      • 1970-01-01
      • 2012-01-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多