Electron环境下SQLite批量插入数据的性能优化方案咨询
问题描述
我遇到的主要问题与性能相关,以下是运行在Electron主进程中的代码:
ipcMain.handle('add_product', async (event, args)=>{ return new Promise((resolve, reject)=>{ try { if(Array.isArray(args)){ args.forEach(prod =>{ const {name,barcode,stock,price,buy_price,image,alert} = prod const stmt = db.prepare("INSERT INTO products VALUES (?,?,?,?,?,?,?)") stmt.run(name, barcode, stock, alert, price, buy_price, image) stmt.finalize() }) resolve({text : `${args.length} product have been added to database!`}) }else{ // This code execute's only when adding a single product // It is not relevant to the question const {name,barcode,stock,price,buy_price,image,alert} = args const stmt = db.prepare("INSERT INTO products VALUES (?,?,?,?,?,?,?)") stmt.run(name, barcode, stock, alert, price, buy_price, image) stmt.finalize() resolve({text : `Product '${name}' have been saved!`}) } }catch (error){ reject(error) } }) })
该代码接收包含产品详情的对象数组,可成功插入数据,但插入5000条以上产品时,应用会卡顿数秒后才恢复响应。我的技术栈为ElectronJS、ReactJS(用于视图层)、SQLite,请问实现高效批量插入的最优方案是什么?
最优批量插入方案
针对SQLite批量插入的性能瓶颈,核心优化方向是复用预编译语句+开启事务,这两个操作能大幅减少重复编译开销和磁盘IO次数,直接解决卡顿问题,具体实现如下:
1. 核心优化点说明
- 复用预编译语句:原代码循环内每次都重新编译SQL语句并销毁,产生大量重复开销。只需在循环外编译一次,循环内重复执行即可。
- 开启数据库事务:SQLite默认单条INSERT为独立事务,会频繁触发磁盘写入。开启事务后,所有插入操作会一次性提交,磁盘IO次数从N次降到1次,性能提升极其显著。
优化后的代码
ipcMain.handle('add_product', async (event, args) => { return new Promise((resolve, reject) => { try { if (Array.isArray(args)) { // 开启事务 db.run('BEGIN TRANSACTION'); // 仅预编译一次插入语句 const stmt = db.prepare("INSERT INTO products VALUES (?,?,?,?,?,?,?)"); args.forEach(prod => { const { name, barcode, stock, price, buy_price, image, alert } = prod; stmt.run(name, barcode, stock, alert, price, buy_price, image); }); stmt.finalize(); // 提交事务,一次性写入磁盘 db.run('COMMIT'); resolve({ text: `${args.length} products have been added to database!` }); } else { // 单条插入逻辑保留(也可复用事务逻辑进一步优化) const { name, barcode, stock, price, buy_price, image, alert } = args; const stmt = db.prepare("INSERT INTO products VALUES (?,?,?,?,?,?,?)"); stmt.run(name, barcode, stock, alert, price, buy_price, image); stmt.finalize(); resolve({ text: `Product '${name}' has been saved!` }); } } catch (error) { // 出错时回滚事务,避免数据不一致 db.run('ROLLBACK'); reject(error); } }); });
额外优化建议
- 分批次插入:如果数据量超过10万条,可将数组拆分为每5000条一批,每批执行一次事务,避免长时间占用主线程导致Electron卡顿。
- 使用异步SQLite API:确保使用支持异步操作的SQLite库(如
sqlite的异步版本),避免同步IO阻塞Electron主进程。 - 临时关闭WAL模式:如果不需要读写并发,批量插入前临时关闭WAL模式(执行
PRAGMA journal_mode=DELETE),完成后再开启,可进一步提升写入速度。
内容的提问来源于stack exchange,提问作者Spetsz_
相关产品推荐
相关产品推荐

