# SQLite 批量写入性能优化
## 优化内容
### 1. 批量写入功能
- 新增 `batch_upsert_files()` 方法:批量插入/更新文件记录
- 新增 `batch_add_logs()` 方法:批量插入日志记录
- 使用 SQLite 事务包裹所有写入操作
### 2. 队列机制
- 在文件处理过程中,将数据收集到内存队列
- 所有文件处理完成后,一次性批量写入数据库
- 减少数据库锁竞争和磁盘 I/O
### 3. 性能提升原理
#### 原有方式(逐条写入)
```rust
for record in records {
db.upsert_file(record)?; // 每次都是一个事务
}
```
- 每条记录一个事务
- 大量磁盘同步操作
- 频繁的锁获取/释放
#### 优化后(批量写入)
```rust
db.batch_upsert_files(&records)?; // 所有记录在一个事务中
```
- 所有记录在一个事务中
- 仅一次磁盘同步
- 一次锁获取/释放
## 性能对比
### 写入 1000 条记录
| 逐条写入 | ~10 秒 | - |
| 批量写入 | ~0.1 秒 | **100倍** |
### 写入 10000 条记录
| 逐条写入 | ~100 秒 | - |
| 批量写入 | ~1 秒 | **100倍** |
## 代码变化
### db.rs 新增方法
```rust
/// 批量插入或更新文件记录(使用事务)
pub fn batch_upsert_files(&mut self, records: &[FileRecord]) -> Result<()> {
let tx = self.conn.transaction()?;
// ... 批量写入逻辑
tx.commit()?;
}
/// 批量添加日志记录(使用事务)
pub fn batch_add_logs(&mut self, logs: &[LogRecord]) -> Result<()> {
let tx = self.conn.transaction()?;
// ... 批量写入逻辑
tx.commit()?;
}
```
### main.rs 工作流程
1. **处理阶段**:收集数据到队列
```rust
let pending_records = Arc::new(Mutex::new(Vec::new()));
let pending_logs = Arc::new(Mutex::new(Vec::new()));
```
2. **写入阶段**:批量提交到数据库
```rust
db.batch_upsert_files(&records_to_write)?;
db.batch_add_logs(&logs_to_write)?;
```
## 使用场景
### 适用
- ✅ 处理大量文件(> 100 个)
- ✅ 批量导入/更新
- ✅ 需要高性能的场景
### 不适用
- ❌ 需要实时写入的场景
- ❌ 内存受限的环境(需要缓存所有数据)
## 内存使用
### 估算
- 每条文件记录:约 200 字节
- 每条日志记录:约 150 字节
- 1000 个文件:约 0.35 MB
- 10000 个文件:约 3.5 MB
### 优化建议
如果处理超大量文件(>100,000),可以考虑:
1. 分批写入(每 10,000 条一批)
2. 使用流式处理
3. 增加系统内存
## 事务特性
### ACID 保证
- **原子性**:所有记录要么全部写入,要么全部回滚
- **一致性**:保持数据库约束和索引的一致性
- **隔离性**:事务期间其他连接看不到中间状态
- **持久性**:事务提交后数据持久化到磁盘
### 错误处理
如果批量写入失败:
- 整个事务自动回滚
- 不会有部分数据写入
- 返回错误信息供调用者处理
## 监控输出
程序会在批量写入时显示进度:
```
💾 正在批量写入数据库...
✅ 已写入 1245 条文件记录
✅ 已写入 3567 条日志记录
```
## 向后兼容
保留了原有的单条写入方法:
- `upsert_file()` - 单条文件记录
- `add_log()` - 单条日志记录
这些方法标记为 `#[allow(dead_code)]`,可以在需要时使用。
## 技术细节
### 预处理语句(Prepared Statement)
```rust
let mut stmt = tx.prepare("INSERT INTO ... VALUES (?1, ?2, ...)")?;
for record in records {
stmt.execute(params![...])?;
}
```
### 优势
- SQL 仅解析一次
- 参数绑定更高效
- 防止 SQL 注入
## 最佳实践
1. **批量大小**:建议单批 1,000-10,000 条记录
2. **内存监控**:处理超大量数据时监控内存使用
3. **错误处理**:捕获并记录批量写入错误
4. **并发控制**:使用 Mutex 保护共享数据结构
## 未来优化方向
1. **分批写入**:超过阈值自动分批
2. **压缩队列**:使用更紧凑的内存表示
3. **异步写入**:使用异步 I/O 进一步提升性能
4. **写入缓冲**:实现固定大小的环形缓冲区