为什么Sequelize在3120条记录之后出现了问题?

时间:2017-11-01 10:08:32

标签: mysql node.js sqlite caching sequelize.js

我有一个用Nodejs编写的系统,它首先要将非常大的csv文件中的记录导入数据库。使用Sequelize作为我的ORM,我创建了一个简单的模型如下:

"use strict";
const Sequelize = require('sequelize');
const sequelize = new Sequelize('mm', 'root', 'password', {
    host: 'localhost',
    dialect: 'mysql',
    logging: true,
    pool: {max: 5, min: 0, idle: 100000},
});
const Index = sequelize.define('index', {
    value: {type: Sequelize.FLOAT}
});

然后我编写了以下代码来循环遍历文件中的行,解释这些行,并将它们写入数据库:

let readline = require('readline');
let moment = require('moment');

let lineReader = readline.createInterface({
    input: require('fs').createReadStream('files/price_index.csv')
});

lineReader.on('line', function (line) {
    let splitted = line.split(',');
    let dt = moment(parseInt(splitted[0]));
    let value = parseFloat(splitted[1]);
    console.log(dt.format(), value);
    Index.create({value: value, createdAt: dt});
});

这样可行,但每3120条记录后暂停约3秒钟。我尝试了sqlite和mysql,但它总是在3120条记录之后暂停。

看到Sequelize在3120条记录之后也开始记录插入查询,我认为这种行为的原因是某种缓存机制,它将所有查询放入队列,直到它要么无关,要么就是它点击魔法查询缓存限制,这正好是3120条记录。

我尝试在Sequelize的初始化中增加pool.max数字,但这似乎没有任何区别。

任何人都可以确认我的缓存想法,或者解释一下这种行为的真正原因是什么?我可以以某种方式更改此行为,以便它具有一致的吞吐量?欢迎所有提示!

1 个答案:

答案 0 :(得分:2)

我认为3120行将是the high water mark for the createReadStream buffer which is 64KiB。当缓冲区已满时,节点将退回读取。

看起来3120 line个事件都在同一个节点事件标记上运行,因此您可以处理3120行和3120个异步Index.create调用以进行下一个滴答。所以你最终会在每一方都做大量的处理。读取和调度查询,或处理大量的计划查询。

当完成3120 line个事件功能时,会发生一些垃圾收集,并且3120个已安排的create个续订呼叫有机会完成他们的工作。这是"暂停"在数据中,但Node仍在处理中。所有create次调用都需要几秒钟才能完成,然后再进行一些垃圾回收并返回到下一个csv数据块及其所有line个事件。这个过程就像那样来回。

在一个包含10000行的csv文件中,我看到~3个查询能够在读取并计划插入所有10000行csv数据之前运行。

一致的吞吐量

您可能希望使用较小块的Readable Stream。然后基于sequelize插入完成阻止读取。您可能需要对自己进行处理,而不是使用readline。如果csv文件适合内存,只需阅读整个内容,因为调度将更容易。

也许使用类似queue的内容来管理插入内容,允许最后一个续集池max作为concurrency。然后,一旦队列的length足够低,允许读取再次发生。

我不知道最终结果是否会更快,但最终可能会非常相似。