Android SQLite插入速度慢于iOS,如何优化大数量插入耗时?
针对你在三星M30s上插入30万条数据耗时11秒,以及实际项目中30秒的问题,结合SQLite的特性,我整理了几个关键优化方向,能帮你大幅提升插入速度:
使用批量INSERT语句减少SQL执行次数
你当前的代码每条数据都执行一次execute(),这会产生大量SQL解析和磁盘IO操作。可以把多条数据合并到一个INSERT语句中,比如每1000条执行一次批量插入,能显著减少SQLite的调用次数。示例代码如下:MyDb myDb = new MyDb(this); SQLiteDatabase db = myDb.getWritableDatabase(); db.beginTransaction(); try { int batchSize = 1000; StringBuilder sb = new StringBuilder("INSERT INTO fieldpoint (pointId, definitionId, modified, value) VALUES "); for (int i = 0; i < count; i++) { sb.append(String.format("(%d, %d, %d, '%s'),", i, i+10, 0, "myDbTest")); // 达到批量阈值就执行一次插入 if ((i + 1) % batchSize == 0) { sb.setLength(sb.length() - 1); // 移除最后一个多余的逗号 db.execSQL(sb.toString()); // 重置StringBuilder准备下一批 sb.setLength(0); sb.append("INSERT INTO fieldpoint (pointId, definitionId, modified, value) VALUES "); } } // 处理剩余不足批量大小的数据 if (sb.length() > "INSERT INTO fieldpoint (pointId, definitionId, modified, value) VALUES ".length()) { sb.setLength(sb.length() - 1); db.execSQL(sb.toString()); } db.setTransactionSuccessful(); } finally { db.endTransaction(); db.close(); myDb.close(); }注意:如果数据包含特殊字符(比如单引号),要做好转义,或者结合参数绑定避免SQL注入风险。
调整SQLite同步模式降低磁盘IO开销
默认的synchronous=FULL会强制每次写入都同步到磁盘,这是为了数据安全,但批量插入时可以临时降低同步级别:db.execSQL("PRAGMA synchronous = NORMAL;");插入完成后再改回
FULL保障数据安全:db.execSQL("PRAGMA synchronous = FULL;");若对临时数据丢失风险接受度高,甚至可以设为
OFF,速度提升会更明显。临时禁用外键约束和触发器
如果你的表有外键约束或触发器,每次插入都会触发额外的检查和操作,拖慢速度。可以在事务开始前临时禁用:db.execSQL("PRAGMA foreign_keys = OFF;");插入完成后再重新开启:
db.execSQL("PRAGMA foreign_keys = ON;");优化WAL模式的使用
你当前开启了WAL,但它更适合高并发读场景。单线程批量插入时,关闭WAL可能获得更好性能:db.disableWriteAheadLogging();若需要保留WAL,也可以用
beginTransactionNonExclusive()替代beginTransaction(),避免独占锁,提升少量效率。复用预编译语句时优化执行逻辑
如果你坚持用预编译语句,可将execute()替换为executeInsert()——它是专门为插入操作设计的,能带来微小的性能提升。同时确保循环内只做必要操作,避免额外的对象创建或计算。
内容的提问来源于stack exchange,提问作者SAM8

