2017-01-22 63 views
2

我正在使用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,我實現了它,現在它正在工作!我會接受你的回答,因爲我認爲這是使用序列而不是批處理的更好實現。 –

回答

1

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

1

我認爲這種天真的方法可行。

嘗試將您的數據分成多個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