将json插入Postgres数据库时发生TimeoutError

时间:2019-02-11 23:15:53

标签: node.js postgresql sequelize.js bulkinsert

我想将文件插入包含对象数组(行)的数据库中。我在25个文件夹中有近8000个文件,近40000条记录。

我收到 TimeoutError:ResourceRequest超时。

我尝试增加续集的连接时间,但在前一千行后给出错误。我怎样才能正确,有效地向本地数据库插入40000行数据?

let folders_path = path.join(__dirname, "extracted_subjects/*");

function bulk_insert() {
  glob(folders_path, readFolders);
}

function readFolders(err, folders) {
  if (err) {
    console.log("ERROR readFolders: ", err);
    return;
  }
  folders.forEach(function(file) {
    glob(path.join(file, "/*.json"), readFiles);
  });
}
function readFiles(err, files) {
  if (err) {
    console.log("ERROR readFiles: ", err);
    return;
  }
  files.forEach(async function(fileName) {
    //console.log(fileName);
    let promise = getData(fileName, "utf8")
      .then(data => {
        try {
          // Parse And Bulk Create
          let obj = JSON.parse(data);
          models.dream
            .bulkCreate(obj)
            .then(function() {
              console.log("File: inserted!");
            })
            .catch(err => console.log("Error", err));
        } catch (SyntaxError) {
          console.log("File: ", fileName);
          return;
        }
      })
      .catch(err => console.log(err));

    await promise;
  });
}

function getData(fileName, type) {
  return new Promise(function(resolve, reject) {
    fs.readFile(fileName, type, (err, data) => {
      err ? reject(err) : resolve(data);
    });
  });
}

1 个答案:

答案 0 :(得分:0)

您可以增加连接的默认设置,例如(您可以阅读文档中的默认设置):

    dialectOptions:   {
      timeout: 30
    },
    operatorsAliases: Sequelize.Op,
    pool:             {
      max:            5,
      min:            0,
      idle:           30000,
      maxConnections: 5,
      maxIdleTime:    30
    },

但是我怀疑您最大的问题是,您正在尝试读取所有文件并继续打开与数据库的新连接,而您没有时间将它们全部写入,并且它们自然会超时

我怀疑这种行为不是您想要写的

files.forEach(async function (fileName) {
  let promise = getData(fileName, 'utf8');
    // ...
  await promise;
});

这部分代码使用的是async和await一词,这不是使它们顺序读取,它们仍然能够并行运行。您将尽快调用getData函数,然后开始轰炸models.dream.bulkCreatebulkCreate的使用在这里没有意义,因为您不是要批量创建任何内容,而是要逐个创建

我可以看到的

选项是:

a)保持类似的代码,但是每块写一次,以25到25的速度并行处理文件,此更改会更大一些,在内存中读取25,在数据库中批量写入,再读取下25,依此类推... < br /> b)保持相似的代码,但是将文件25乘25并行读取,每块25写入,此更改会更大一些,打开并读取25个文件,然后每写入一个文件仅一行,然后继续
c)保留相似的代码,但不要读取每个文件并将其写入数据库,而是将它们保存在内存中,并在拥有所有数据后最后一次将所有数据写入一次。但是,在这种大数据的情况下,您可能会用完内存
d)如果性能不是问题,因为您想要(或需要)(一次)执行一次,您可以简单地循环浏览所有文件并以同步模式读取它们,因此它总是一个接一个地运行。 >

files.forEach(async function (fileName) {
  let data = fs.readFileSync(fileName, 'utf8'); // read the file sync

  try {
    let parsedData = JSON.parse(data); // try parsing
    models.dream                       // and inserting 
      .create(parsedData)              // this should not be bulkCreate, right??
       // this is kinda wrong, it doesn't automatically mean it 
       // is inserted, but it is copy paste from above
      .then(res => console.log('File: inserted!')) 
      .catch(err => console.log('Error', err));
  } catch (SyntaxError) {console.log('File: ', fileName);}
};

这段代码正在做的是确保您实际上按顺序逐个文件运行,这将大大降低您的执行速度,但是由于您最初表示要在本地主机上执行此操作,所以我认为您有时间让它继续运行。您仍然冒着读取文件的速度快于数据库处理文件的速度的风险,但是这次与下一个文件的同步读取相差无几,并且系统应该能够保持同步,特别是如果您增加允许的数量连接池中。

在生产方面,我可能会选择选项a或b,这取决于我是否提前知道最大文件大小/文件数。