小、快、稳的SQLite数据库

SQLite 数据库口碑好,是有道理的。我的评价是:它不是“小玩具数据库”,而是非常成熟、可靠、适合嵌入式和本地应用的数据存储方案;但它也不是 MySQL/PostgreSQL 那种多用户高并发服务端数据库的替代品。

SQLite 的核心优点是:小、快、稳、免维护。官方对它的定位就是一个“自包含、无服务器、零配置、事务型 SQL 数据库引擎”,而且代码是公有领域,可免费用于商业或私人用途。SQLite 也自称是世界上部署最广泛的数据库之一,被内置在手机、电脑和大量应用中。(SQLite官网)

小、快、稳的SQLite数据库

它特别适合这些场景:桌面软件、本地工具、移动 App、嵌入式设备、IoT 设备、边缘采集设备、单机数据缓存、配置存储、日志索引、实验数据管理等。SQLite 官方也明确把“嵌入式设备和物联网”列为非常适合的使用场景,因为它不需要数据库管理员、不需要单独安装数据库服务,非常适合无人值守设备。(SQLite官网)

工业设备监测场景中,SQLite 很合适。比如存储任务信息、采样摘要、事件记录、报警记录、模型识别结果、传感器数据索引、短期原始采样数据,都可以用 SQLite。它的单文件数据库也便于备份、拷贝、导出、现场排查,配合 Qt/C++、Python 都很方便。

但 SQLite 的短板也要明确:写并发能力有限。它可以有多个读者,但写入本质上是串行的。官方文档说明,写入数据库文件时需要排他锁;WAL 模式可以改善并发,使读写可以同时进行,但并不等于支持多个写入者同时写。(SQLite官网)

所以,如果你的系统是这样的:一个采集线程持续写入,一个 UI 线程查询显示,一个导出线程偶尔读取,SQLite 很合适;但如果是几十个客户端、多个进程、多个服务同时高频写入同一个数据库文件,那就不适合,应该考虑 PostgreSQL、MySQL、TimescaleDB、InfluxDB 等服务端数据库或时序数据库。

对于采样数据,尤其是 1000Hz 加速度这类高频数据,SQLite 也能用,但要注意方法。不要每个采样点单独提交一次事务,而应该使用:

PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;

并且采用批量插入、预编译 SQL、事务提交、合理索引。例如每 100 条、500 条、1000 条样本批量写一次,比逐条提交稳定得多。原始波形数据量特别大时,也可以考虑“SQLite 存任务和索引,CSV/二进制文件存大块原始波形”的混合方案。

我的总体判断:

维度评价
稳定性很高
易部署极高
维护成本极低
查询能力对本地应用足够强
嵌入式适配非常好
多用户高并发不适合
高频采样原始数据可以用,但要批量写入和控制库大小
工业现场设备很适合本地缓存、任务记录、结果存储

结论:SQLite 的好口碑主要来自“可靠、简单、少出问题”。它最强的地方不是大规模并发,而是单机、本地、嵌入式、边缘端场景中的稳定和省心。 对你的设备监测类软件来说,SQLite 是一个很好的默认选择;只要避免“多线程/多进程同时高频写入同一个库”这种误用,它完全可以作为正式产品的数据存储方案。


WAL 模式简介

WAL 是 Write-Ahead Logging 的缩写,中文通常叫 预写日志模式。在 SQLite 里,它是一种日志机制,用来提高数据库的读写并发能力和写入效率。

SQLite 默认常见模式是 Rollback Journal 回滚日志模式。在这种模式下,写入数据前,SQLite 会先把原来的页面内容保存到一个 journal 文件里;如果写入失败,就用 journal 文件恢复原状。

而 WAL 模式的思路不一样:不直接修改主数据库文件,而是先把变更写到一个单独的 WAL 日志文件中。读操作仍然可以读取主数据库文件,同时结合 WAL 文件中的最新变更得到正确结果。

可以简单理解为:

普通模式:
写入时直接改数据库文件,需要更强的锁控制。

WAL 模式:
先把修改写到 .wal 日志文件;
之后再择机合并回主数据库文件。

启用 WAL 后,一个 SQLite 数据库通常会出现这些文件:

data.db        主数据库文件
data.db-wal    WAL 日志文件
data.db-shm    共享内存辅助文件

WAL 模式最大的好处是:读和写可以更好地并行。在传统模式下,写入时容易阻塞读取;而 WAL 模式下,写入追加到 WAL 文件,读取者通常还能继续读取数据库快照。因此对于“一个线程持续写入,另一个线程查询显示”的本地应用,WAL 很有价值。

它的典型优点有:

优点说明
读写并发更好写入时不容易阻塞读取
写入性能通常更好写入是追加日志,顺序写入效率较高
崩溃恢复可靠数据先写日志,异常断电后可恢复
适合本地应用很适合桌面软件、嵌入式设备、设备监测、日志记录等场景

但要注意,WAL 并不是让 SQLite 变成高并发服务器数据库。它仍然有一个重要限制:同一时间通常仍然只有一个写入者。也就是说,WAL 改善的是“读写并发”,不是“多个写线程同时高频写入”。

启用方式很简单:

PRAGMA journal_mode=WAL;

常见搭配是:

PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;

其中:

PRAGMA synchronous=NORMAL;

表示在性能和安全之间做一个较好的平衡。对于很多本地应用和设备监测系统,这个组合比较常用。

WAL 模式还有一个概念叫 checkpoint,中文可理解为“检查点”或“合并点”。因为数据先写入 .wal 文件,SQLite 需要在合适的时候把 WAL 文件里的内容合并回主数据库文件。这个过程就叫 checkpoint。

可以手动执行:

PRAGMA wal_checkpoint;

也可以执行更彻底的:

PRAGMA wal_checkpoint(TRUNCATE);

后者会尽量把 WAL 内容合并回主库,并截断 WAL 文件,避免 .wal 文件长期变大。

在实际使用中,建议这样理解 WAL:

WAL = 先写日志,再合并数据库。

它特别适合:

一个采集线程持续写入数据;
一个界面线程实时查询显示;
一个导出线程偶尔读取历史数据。

这类场景中,WAL 可以减少“写入时界面查询卡住”的问题。

不过使用 WAL 时也要注意几点:

注意点说明
不要多个进程疯狂写同一个库SQLite 仍然不是高并发服务端数据库
不要每条数据单独提交事务高频数据应批量写入
注意 WAL 文件大小必要时做 checkpoint
数据库文件、wal、shm 要一起看待运行中不能只复制 .db 文件而忽略 .wal
网络文件系统慎用SQLite 官方长期不建议在不可靠的网络文件系统上使用复杂锁机制

对于设备监测类软件,我的建议是:

PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;

然后采用批量插入,例如每 100 条、500 条或 1000 条数据提交一次事务,而不是每条数据单独提交。

示意:

BEGIN TRANSACTION;

INSERT INTO samples(time_ms, value) VALUES (...);
INSERT INTO samples(time_ms, value) VALUES (...);
INSERT INTO samples(time_ms, value) VALUES (...);

COMMIT;

一句话总结:WAL 模式就是 SQLite 的“追加日志写入模式”,它能明显改善本地数据库的读写并发表现,特别适合本地应用、嵌入式设备和设备监测场景;但它不能把 SQLite 变成 MySQL/PostgreSQL 那样的多用户高并发服务端数据库。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

Are you human? Please solve:Captcha