GridDB容器加载CSV文件时遭遇事务超时错误求助
GridDB事务超时问题分析与解决方案
你遇到的事务超时并非直接由内存限制导致,而是代码中存在的几个关键逻辑错误引发的资源过载和频繁事务操作,以下是具体分析和修复方案:
核心问题原因
- 重复创建容器与索引:在循环中每次都调用
store.putContainer和createIndex,这会重复执行容器创建(即使容器已存在)和索引创建操作,浪费大量服务器资源,同时引发不必要的锁竞争。 - 单条数据独立事务:每插入一行数据就开启并提交一次事务,对于大量数据来说,频繁的事务提交会大幅增加GridDB的处理负载,触发事务超时阈值。
- 异步请求并发过载:for循环同步执行,但内部的Promise操作是异步的,会同时发起大量的容器操作和事务请求,服务器无法及时处理这些并发请求,导致超时。
- 内存间接影响:如果CSV数据量极大,
lst.push(row)会将所有数据加载到内存,可能导致Node.js进程内存占用过高,间接降低数据插入的处理速度,加剧超时问题。
修复方案
- 提前初始化容器与索引:容器和索引只需要创建一次,放在CSV读取完成后、数据插入前执行。
- 批量事务插入:开启一个事务,一次性插入所有数据(或分批次插入),最后统一提交事务,减少事务开销。
- 异步流程控制:使用
async/await确保异步操作顺序执行,避免并发请求过载。 - 内存优化(可选):如果数据量极大,改为流式插入,边读取CSV行边插入,无需将所有数据加载到内存。
修改后的代码示例
var griddb = require('griddb-node-api'); const createCsvWriter = require('csv-writer').createObjectCsvWriter; const csv = require('csv-parser'); const fs = require('fs'); const csvWriter = createCsvWriter({ path: 'out.csv', header: [ {id: "Country", title:"Country"}, {id: "1999", title:"1999"}, {id: "2000", title:"2000"}, {id: "2001", title:"2001"}, {id: "2002", title:"2002"}, {id: "2003", title:"2003"}, {id: "2004", title:"2004"}, {id: "2005", title:"2005"}, {id: "2006", title:"2006"}, {id: "2007", title:"2007"}, {id: "2008", title:"2008"}, {id: "2009", title:"2009"}, {id: "2010", title:"2010"}, {id: "2011", title:"2011"}, {id: "2012", title:"2012"}, {id: "2013", title:"2013"}, {id: "2014", title:"2014"}, {id: "2015", title:"2015"}, {id: "2016", title:"2016"}, {id: "2017", title:"2017"}, {id: "2018", title:"2018"}, {id: "2019", title:"2019"}, {id: "2020", title:"2020"}, {id: "2021", title:"2021"}, {id: "2022", title:"2022"}, ] }); const factory = griddb.StoreFactory.getInstance(); const store = factory.getStore({ "host": '239.0.0.1', "port": 31999, "clusterName": "defaultCluster", "username": "admin", "password": "admin" }); const conInfo = new griddb.ContainerInfo({ 'name': "gdpanalysis", 'columnInfoList': [ ["name", griddb.Type.STRING], ["Country", griddb.Type.STRING], ["1999", griddb.Type.DOUBLE], ["2000", griddb.Type.DOUBLE], ["2001", griddb.Type.DOUBLE], ["2002", griddb.Type.DOUBLE], ["2003", griddb.Type.DOUBLE], ["2004", griddb.Type.DOUBLE], ["2005", griddb.Type.DOUBLE], ["2006", griddb.Type.DOUBLE], ["2007", griddb.Type.DOUBLE], ["2008", griddb.Type.DOUBLE], ["2009", griddb.Type.DOUBLE], ["2010", griddb.Type.DOUBLE], ["2011", griddb.Type.DOUBLE], ["2012", griddb.Type.DOUBLE], ["2013", griddb.Type.DOUBLE], ["2014", griddb.Type.DOUBLE], ["2015", griddb.Type.DOUBLE], ["2016", griddb.Type.DOUBLE], ["2017", griddb.Type.DOUBLE], ["2018", griddb.Type.DOUBLE], ["2019", griddb.Type.DOUBLE], ["2020", griddb.Type.DOUBLE], ["2021", griddb.Type.DOUBLE], ["2022", griddb.Type.DOUBLE] ], 'type': griddb.ContainerType.COLLECTION, 'rowKey': true }); // 处理CSV加载与GridDB插入的主函数 async function processData() { try { // 1. 提前创建容器并初始化索引(仅执行一次) const container = await store.putContainer(conInfo, false); await container.createIndex({ 'columnName': 'name', 'indexType': griddb.IndexType.DEFAULT }); // 2. 读取CSV数据(可选:如果数据极大,可改为流式插入) const lst = []; await new Promise((resolve, reject) => { fs.createReadStream('./Dataset/GDP by Country 1999-2022.csv') .pipe(csv()) .on('data', (row) => lst.push(row)) .on('end', resolve) .on('error', reject); }); // 3. 开启事务,批量插入所有数据 container.setAutoCommit(false); for (let i = 0; i < lst.length; i++) { const row = lst[i]; await container.put([ String(i + 1), row['Country'], row["1999"], row["2000"], row["2001"], row["2002"], row["2003"], row["2004"], row["2005"], row["2006"], row["2007"], row["2008"], row["2009"], row["2010"], row["2011"], row["2012"], row["2013"], row["2014"], row["2015"], row["2016"], row["2017"], row["2018"], row["2019"], row["2020"], row["2021"], row["2022"] ]); } await container.commit(); console.log("所有数据插入完成"); // 4. 查询数据并生成输出CSV const query = container.query("select *"); const rs = await query.fetch(); const lst2 = []; while (rs.hasNext()) { const rsNext = rs.next(); lst2.push({ 'Country': rsNext[1], "1999": rsNext[2], "2000": rsNext[3], "2001": rsNext[4], "2002": rsNext[5], "2003": rsNext[6], "2004": rsNext[7], "2005": rsNext[8], "2006": rsNext[9], "2007": rsNext[10], "2008": rsNext[11], "2009": rsNext[12], "2010": rsNext[13], "2011": rsNext[14], "2012": rsNext[15], "2013": rsNext[16], "2014": rsNext[17], "2015": rsNext[18], "2016": rsNext[19], "2017": rsNext[20], "2018": rsNext[21], "2019": rsNext[22], "2020": rsNext[23], "2021": rsNext[24], "2022": rsNext[25] }); } await csvWriter.writeRecords(lst2); console.log('The CSV file was written successfully'); } catch (err) { if (err.constructor.name == "GSException") { for (var i = 0; i < err.getErrorStackSize(); i++) { console.log("[", i, "]"); console.log(err.getErrorCode(i)); console.log(err.getMessage(i)); } } else { console.log(err); } } } // 执行主函数 processData();
内容的提问来源于stack exchange,提问作者Emad Bin Abid
相关产品推荐
相关产品推荐

