C#中SQLiteDataAdapter批量插入性能低下问题求助
我有一个包含约25-30K条数据的JSON文件,需要存入SQLite数据库。使用SQLiteDataAdapter通过DataTable插入15K条数据耗时约35分钟,当前UpdateBatchSize为1,尝试修改时触发"Specified method is not supported"异常。以下是我的Update方法代码:
public async Task<bool> SaveTable() { SQLiteDataAdapter data_adapter = null; try { data_adapter = new SQLiteDataAdapter(sql_cmd); data_adapter.UpdateBatchSize = 10; } catch (Exception e) { Console.WriteLine("Exception Thrown: " + e.Message); return false; } try { SQLiteCommandBuilder cmd_bldr = new SQLiteCommandBuilder(data_adapter); data_adapter.InsertCommand = cmd_bldr.GetInsertCommand(); Console.WriteLine(data_adapter.InsertCommand.CommandText); data_adapter.AcceptChangesDuringUpdate = true; data_adapter.UpdateCommand = data_adapter.InsertCommand; } catch (Exception e) { Console.WriteLine("Exception Thrown: " + e.Message); return false; } try { var size = data_adapter.UpdateBatchSize; Console.WriteLine("Updating Table. Batch Size: " + size); var rows_updated = data_adapter.Update(data_table); Console.WriteLine("Rows Updated: " + rows_updated.ToString()); data_adapter.Dispose(); } catch(Exception e) { Console.WriteLine("Exception Thrown: " + e.Message); return false; } return true; }
请问是否可以修改UpdateBatchSize,或者有其他方法提升每秒插入数据的次数?
首先得明确:SQLiteDataAdapter并不支持批量更新(UpdateBatchSize),这就是你触发"Specified method is not supported"异常的原因——这个组件的设计就没实现批量操作的功能,别在这上面浪费时间了。
接下来给你几个能大幅提升插入效率的方法,按优先级排序:
1. 使用事务 + 批量SQL语句
这是提升SQLite插入速度最有效的手段之一,原理是把所有插入操作放在一个事务里(SQLite默认每一条语句都开启一个事务,开销极大),同时拼接批量插入的SQL(比如INSERT INTO table (col1, col2) VALUES (val1,val2), (val3,val4), ...)。
举个简单的实现思路:
- 先把DataTable里的行分组,每组比如1000条(别太大,避免SQL语句过长)
- 开启一个SQLite事务
- 对每个分组,拼接成一条批量插入的SQL命令,执行
- 最后提交事务
代码示例片段:
using (var conn = new SQLiteConnection(yourConnectionString)) { conn.Open(); using (var transaction = conn.BeginTransaction()) { var command = conn.CreateCommand(); command.Transaction = transaction; // 分组处理DataTable行 int batchSize = 1000; for (int i = 0; i < data_table.Rows.Count; i += batchSize) { var batchRows = data_table.Rows.Cast<DataRow>().Skip(i).Take(batchSize); // 拼接批量INSERT语句(实际项目一定要用参数化,避免SQL注入!) var valuesClauses = new List<string>(); foreach (var row in batchRows) { var param1 = command.CreateParameter(); param1.ParameterName = $"@val1_{i}"; param1.Value = row["Col1"]; var param2 = command.CreateParameter(); param2.ParameterName = $"@val2_{i}"; param2.Value = row["Col2"]; command.Parameters.Add(param1); command.Parameters.Add(param2); valuesClauses.Add($"({param1.ParameterName}, {param2.ParameterName})"); } command.CommandText = $"INSERT INTO YourTable (Col1, Col2) VALUES {string.Join(", ", valuesClauses)}"; await command.ExecuteNonQueryAsync(); command.Parameters.Clear(); } transaction.Commit(); } }
2. 临时调整SQLite同步模式
SQLite默认的同步模式是FULL,安全性拉满但写入速度慢。如果你的场景可以接受短暂降低同步级别(比如插入完成后能验证数据完整性),可以临时改成OFF或NORMAL,插入结束后再恢复:
using (var conn = new SQLiteConnection(yourConnectionString)) { conn.Open(); using (var cmd = conn.CreateCommand()) { // 临时降低同步级别 cmd.CommandText = "PRAGMA synchronous = NORMAL;"; await cmd.ExecuteNonQueryAsync(); // 执行批量插入操作... // 恢复默认同步模式 cmd.CommandText = "PRAGMA synchronous = FULL;"; await cmd.ExecuteNonQueryAsync(); } }
3. 启用WAL日志模式
启用Write-Ahead Logging(WAL)模式可以让SQLite支持并发读写,同时显著提升写入性能。这个设置会持久化到数据库文件,只需执行一次:
using (var conn = new SQLiteConnection(yourConnectionString)) { conn.Open(); using (var cmd = conn.CreateCommand()) { cmd.CommandText = "PRAGMA journal_mode = WAL;"; await cmd.ExecuteNonQueryAsync(); } }
4. 跳过DataTable中转
DataTable是比较重的组件,如果能直接把JSON序列化为实体类列表,再直接操作实体类进行批量插入,会比通过DataTable中转更快。比如用System.Text.Json或Newtonsoft.Json解析JSON到List<YourModel>,再按上面的批量方式插入。
最后再提醒一句:所有涉及外部输入的数据,一定要用参数化查询,绝对不能直接拼接SQL字符串,避免SQL注入风险!
内容的提问来源于stack exchange,提问作者Moth

