带有 pg-promise 的大量插入

Massive inserts with pg-promise

我正在使用 pg-promise and I want to make multiple inserts to one table. I've seen some solutions like and ,我可以使用 pgp.helpers.concat 来连接多个选择。

但是现在,我需要在 table 中插入很多测量值,其中有超过 10,000 条记录,并且在 https://github.com/vitaly-t/pg-promise/wiki/Performance-Boost 中说: "How many records you can concatenate like this - depends on the size of the records, but I would never go over 10,000 records with this approach. So if you have to insert many more records, you would want to split them into such concatenated batches and then execute them one by one."

我阅读了所有文章,但我不知道如何 "split" 我的插入到批处理中,然后一个一个地执行它们。

谢谢!

我认为天真的方法会奏效。

尝试将您的数据拆分为多条 10,000 条或更少的记录。 我会尝试使用 post.

中的解决方案拆分数组

然后,multi-row用插入每个数组,并在一个事务中一个一个执行。

编辑:感谢@vitaly-t 提供了很棒的库并改进了我的回答

Also don't forget to wrap your queries in a transaction, or else it will deplete the connections.

为此,请使用 pg-promise 中的 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;
});

更新

最好阅读以下文章:Data Imports


作为 pg-promise 的作者,我不得不最终为这个问题提供正确的答案,因为之前发布的答案并没有真正做到公正。

为了插入 massive/infinite 条记录,您的方法应该基于方法 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,到return 一次大约 1,000 - 10,000 个对象,具体取决于对象的大小和数据可用性。

另请参阅一些 API 示例:


相关问题:.


如果您需要获取所有插入记录的生成 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-s 会造成过载。