SQLite 插入百万级数据慢怎么优化事务批量提交

文章导读
最推荐的做法是显式开启事务批量提交,并配合 PRAGMA 参数调整磁盘同步策略,这能从根本上减少磁盘 I/O 次数。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 参考来源
A A

最推荐的做法是显式开启事务批量提交,并配合 PRAGMA 参数调整磁盘同步策略,这能从根本上减少磁盘 I/O 次数。

先说结论:单条插入慢是因为每条都默认提交事务,改为批量事务提交可大幅提升效率,但需注意数据安全配置。

  • 先定位:确认代码是否每条 INSERT 都自动_commit_
  • 先做:使用 BEGIN TRANSACTION 包裹批量写入
  • 再验证:对比耗时并检查数据完整性

命令速用版

若在 SQLite 命令行或脚本中操作,可参考以下结构:

BEGIN TRANSACTION;
INSERT INTO table_name VALUES (...);
INSERT INTO table_name VALUES (...);
COMMIT;

若使用命令行导入大量数据,可配合以下参数调整:

sqlite3> PRAGMA synchronous = NORMAL;
sqlite3> PRAGMA journal_mode = WAL;
sqlite3> .import file.csv table_name

为什么会这样

SQLite 默认每执行一条 INSERT 语句就会进行一次事务提交,这意味着每次写入都要刷盘(fsync)。公开资料中没有看到可靠的量化数据适用于所有硬件,但 SQLite 官方文档提到,关闭自动提交后,写入速度可能有数量级的提升。

SQLite 插入百万级数据慢怎么优化事务批量提交

主要原因在于磁盘 I/O 开销。事务提交需要写日志并同步到磁盘,批量提交将多次同步合并为一次,显著减少了等待时间。

分步处理

1. 代码层开启事务

在循环插入前手动开启事务,循环结束后统一提交。不同语言的具体写法略有不同,但逻辑一致。

db.execute("BEGIN TRANSACTION")
for row in data:
    db.execute("INSERT INTO ...", row)
db.execute("COMMIT")

2. 调整 PRAGMA 参数

在连接建立后执行以下设置,注意同步模式影响安全性。建议在写入前设置,写入后可根据需要恢复。

SQLite 插入百万级数据慢怎么优化事务批量提交
PRAGMA synchronous = NORMAL;
PRAGMA journal_mode = WAL;

3. 使用预编译语句

避免每次插入都重新编译 SQL 语句,使用 prepare statement 可以减少 CPU 开销。

怎么验证是否生效

1. 记录插入开始和结束时间,计算耗时,对比优化前后的差异。

2. 使用SELECT count(*) FROM table_name;确认数据条数无误,防止事务中途失败导致数据丢失。

SQLite 插入百万级数据慢怎么优化事务批量提交

3. 运行PRAGMA integrity_check;确保数据库未损坏,特别是在调整了同步策略后。

常见坑

1. 数据丢失风险:synchronous设为OFF虽快,但断电可能导致数据库损坏,生产环境慎用。

2. 锁竞争:事务未提交期间会锁住数据库,影响并发读取,长事务需谨慎。

3. 内存占用:批量过大可能占用过多内存,建议分批次提交(如每 1000 条提交一次),避免一次性提交百万条。

参考来源

  • SQLite 官方文档:Speed of SQLite, https://www.sqlite.org/speed.html
  • SQLite 官方文档:PRAGMA statements, https://www.sqlite.org/pragma.html