pg-promise海量插入

问题描述:

我正在使用pg-promise,我想对一个表进行多次插入。我见过一些解决方案,如Multi-row insert with pg-promiseHow do I properly insert multiple rows into PG with node-postgres?,我可以使用pgp.helpers.concat来连接多个选择。pg-promise海量插入

但现在,我需要插入了大量的测量,在表中,有超过10,000条记录,并在https://github.com/vitaly-t/pg-promise/wiki/Performance-Boost说: “你怎么可以对多条记录串连这样的 - 取决于记录的大小,但我不会用这种方法去超过10,000条记录,所以如果你必须插入更多的记录,你可能希望将它们拆分成这样的连续批次,然后逐个执行它们。“

我阅读所有文章,但我无法弄清楚如何将我的插入“拆分”为批次,然后逐个执行它们。

谢谢!

+0

比从未更好的迟到,因为我终于有时间重新阅读您的问题,并在现有的[pg-promise](https://github.com/vitaly-t/pg-promise)API中提供正确的答案;) –

+0

非常感谢您的回复@ vitaly-t,我实现了它,现在它正在工作!我会接受你的回答,因为我认为这是使用序列而不是批处理的更好实现。 –

UPDATE

最好的是阅读下面的文章:Data Imports


由于pg-promise我身不由己,最后给出了正确答案的问题笔者,作为一个早些时候发表并没有真正做到公正。

为了插入大量/无限数量的记录,您的方法应基于方法sequence,这在任务和事务中可用。

var cs = new pgp.helpers.ColumnSet(['col_a', 'col_b'], {table: 'tableName'}); 

// returns a promise with the next array of data objects, 
// while there is data, or an empty array when no more data left 
function getData(index) { 
    if (/*still have data for the index*/) { 
     // - resolve with the next array of data 
    } else { 
     // - resolve with an empty array, if no more data left 
     // - reject, if something went wrong 
    }   
} 

function source(index) { 
    var t = this; 
    return getData(index) 
     .then(data => { 
      if (data.length) { 
       // while there is still data, insert the next bunch: 
       var insert = pgp.helpers.insert(data, cs); 
       return t.none(insert); 
      } 
      // returning nothing/undefined ends the sequence 
     }); 
} 

db.tx(t => t.sequence(source)) 
    .then(data => { 
     // success 
    }) 
    .catch(error => { 
     // error 
    }); 

这是从性能角度和负载调节两方面向数据库中插入大量行的最佳方法。

您所要做的就是根据您的应用的逻辑实现您的功能getData,即根据序列的index,您的大数据来自何处,以一次返回大约1,000-10,000个对象,取决于对象的大小和数据的可用性。

也看到一些API的例子:


相关问题:node-postgres with massive amount of queries


而且在您需要获得所有插入的记录生成的ID-S的情况下,你会改变两行如下:

// return t.none(insert); 
return t.map(insert + 'RETURNING id', [], a => +a.id); 

// db.tx(t => t.sequence(source)) 
db.tx(t => t.sequence(source, {track: true})) 

刚要小心,因为在记忆中保留太多记录ID可能会造成过载。

+0

感谢您的回应!最后,我已经实现了你的回应,并且它的工作完美。如果我的数组信息存储在一个数组中,我可以省略调用getData函数,只需在源代码中给定索引,就可以返回主数组中的下一个数据数组?如果(index

我认为这种天真的方法可行。

尝试将您的数据分成多个10,000条或更少的记录。 我会尝试使用此解决方案从这个post分裂阵列。

然后,多行插入每个数组与pg-promise并在事务中一个接一个地执行它们。

编辑:感谢@ vitaly-t为美妙的图书馆和改善我的回答

另外不要忘记在事务中包装您的查询,否则它会耗尽连接。

要做到这一点,请使用PG-诺言batch功能以异步方式解决所有问题:

// split your array here to get splittedData 
int i = 0 
var cs = new pgp.helpers.ColumnSet(['col_a', 'col_b'], {table: 'tmp'}) 

// values = [..,[{col_a: 'a1', col_b: 'b1'}, {col_a: 'a2', col_b: 'b2'}]] 
let queries = [] 
for (var i = 0; i < splittedData.length; i++) { 
    var query = pgp.helpers.insert(splittedData[i], cs) 
    queries.push(query) 
} 

db.tx(function() { 
    this.batch(queries) 
}) 
.then(function (data) { 
    // all record inserted successfully ! 
} 
.catch(function (error) { 
    // error; 
}); 
+0

好的,谢谢你的帖子!我明白了,但是我仍然没有形象化下一个MultiRowInsert()函数,它应该是你提交的代码的递归函数,直到我没有更多的数据为止。 –

+1

你必须在交易中完成它,否则它将耗尽连接。 –

+0

@ vitaly-t好点。我将编辑我的答案 – AlexB