sqlite journal恢复数据_sqlite 性能优化

本文详细探讨了SQLite数据库的性能优化策略,包括显示调用事务、磁盘同步设置、内存模式、journal_model的选择、page_size和cache_size的调整以及mmap_size的优化。同时,提到了优化表结构、提升硬件性能和优化应用程序负载对提升查询速度的重要性。总结了多种优化方式,建议根据具体需求选择合适的方法。
摘要由CSDN通过智能技术生成
测试环境  CPU:Inter(R) Core(TIM) i3-2120 CPU@3.3GHz 内存:8GB 操作系统:Deepin
显示调用事务
利用事务的互斥性,在批量操作时显示开启事务,操作结束后提交事务,那么所有操作将只执行一次事务,大大提高IO效率。
sqlite3_exec(db, "BEGIN;", 0, 0, NULL);for( i = 0; i 10000; i++)
{
   ...
   sqlite3_exec(db, sqlcmd, NULL, NULL, &zErr);
}
sqlite3_exec(db, "COMMIT;", 0, 0, NULL);
磁盘同步 (synchronous)
synchronous 获取或者设置当前磁盘同步模式,该模式用于控制SQlite写入磁盘的时机。
Pragma 值说明
0或者OFF不进行同步。写入数据后传递给操作系统则完成操作,类似mmap,剩下的交给操作系统完成
1 或者NORMALsqlite2 的默认模式,在关键磁盘的每个序列后同步。不像FULL模式那么频繁刷盘,有小几率在电源故障或者磁盘不可用时导致数据库损坏
2 或者 FULLsqlite3 默认模式,在每个关键磁盘操作后同步,性能差。数据库在紧急时刻暂停以确定数据写入磁盘,使得系统崩溃或者电源出问题时,确保数据库重启不会损坏
当 我们对数据丢失情况不太敏感,可将 synchronous 设置为 off,写入性能可提高3倍。
内存模式(temp_store)
Pragma 值说明
0 或者DEFAULT使用编译时的C预处理宏 TEMP_STORE来定义储存临时表和临时索引的位置
1 或者FILE则存放于文件中。temp_store_directory pragma 可用于指定存放该文件的目录
2 或者 MEMORY临时表和索引则存放于内存中
journal_model 设置
journal_mode 获取或者设置控制日志文件如何存储和处理的日志模式。journal 为的是数据库事务的rollback操作,数据库begin trans写入时,首先写入journal 文件中,commit 操作时,根据journal-model来处理日志文件。如果在commit之前由于断电等原因造成无法commit,当再次启动时,可通过journal文档做回滚操作,保证数据库的完整性和一致性。
Pragma 值说明
DELETE默认模式。事务结束时,日志文件删除
TRUNCATE日志文件被截断为0字节长度
PRESIST日志文件保留在原地,但头部被重写,表明日志不再有效
MEMORY日志文件记录在内存中,而不是磁盘
OFF不保留任务日志
WALwrite ahead log。
  • DELETE:读写操作时DEL模式要处理各种锁。写操作是独享的,写阻塞读;读完成时才能写,读阻塞写。
  • WAL:修改不直接写入数据库文件中,而是直接一个WAL文件中,若事务失败,WAL记录被忽略;若事务成功,随后在某个checkpoint时间点写回数据。若要继续提升性能,可修改checkpoint.
page_size 和 cache_size
  • page_size:分页大小。默认page_size = 4096。其值为512、1024、2048、4096、8192、16384、32768、65536.
  • cache_size:表示在缓存中的页面数,内置页面缓存的默认大小为 2,000 页,最小尺寸为 10 页。

注意:

  • 通 PRAGMA page_size/cache_size 能够查询当前页大小和缓存size;
  • PRAGMA cache_size = xxx ,可动态设置缓存大小,仅当前数据库链接有效;
  • page_size:在创建数据库表时设置即可生效。sqilte3.5.8 以后,通过PRAGMA cache_size =xxx 后,执行 VACUUM, 也可动态修改页大小。如果未执行VACCUM,页大小修改无效。
  • page_size 和 cache_size 不是越大越好。具体要结合硬件缓存以及数据库记录。
  • page_size 决定着数据库最小储存单元page的大小。当查询记录大小大于page_size 时,此时需要多次寻址才能完成本次操作,如果page_size 大于 查询记录大小,一次寻址即可。
  • 理论上page_size 和 cache_size 越大越好,实际根据应用场景和硬件资源来调整这两个参数。当缓存足够大的时候,一次查询能够直接命中数据库最后一条记录,在向上调整就没有效果了;当缓存和内存资源紧张,特别是嵌入设备,根据实际场景调整,page_size 设置尽量接近需要频繁查询的记录大小。然后调整cache_size,这样也可以一定程度控制数据库大小。

以下对轻量级数据库做了一个简要测试:

e19849ba0d2bb525dd4f8b14af3a1b85.png
mmap_size

mmap对I/O性能的提升无需赘言,尤其是对于读操作。SQLite也在OS层封装了mmap的接口,可以无缝地切换mmap和普通的I/O接口。只需配置PRAGMA mmap_size=XXX即可开启mmap。

03f87e42294e6480ed4f8502dce90aad.png
其他
  • 优化表的结构:比如将 blob 字段,放在数据库末尾,尽量降低blob大小;
  • 提升 CPU 和 DDR 频率,对于嵌入式平台,CPU频率对数据库查询速率影响较大。适当的提高CPU频率会大大提升查询性能;
  • 优化应用程序负载,降低CPU 和 DDR 负担,在测试时发现,自己写的测试demo速度优化很明显,一加入到项目中,发现查询速度又降下来了,排查发现有个线程对CPU的资源消耗非常大,适当的降低其占用CPU时间,查询速度立马起来了。
总结

本文介绍了sqlite 常见的几种优化性能的方式:

  • 事务
  • 磁盘同步
  • temp_store
  • journal_mode
  • page_size 和 cache_size
  • mmap_size

结合自身需求,选择适合自己的方式!最后放一个sqlite c源码链接,感兴趣的自行下载:http://www3.sqlite.org/index.html

`sqlite3_wal_checkpoint`函数只能用于WAL模式下的检查点操作,而对于journal文件,可以使用`sqlite3_wal_checkpoint_v2`函数或`sqlite3_wal_hook`函数来进行处理。以下是一个示例: ``` #include <stdio.h> #include <sqlite3.h> static int wal_hook(void *pArg, sqlite3 *db, const char *zDb, int nFrame) { int rc = SQLITE_OK; char *err_msg = 0; // 检查并清除journal文件 rc = sqlite3_exec(db, "PRAGMA journal_mode = OFF;", NULL, NULL, &err_msg); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot turn off journal mode: %s\n", err_msg); sqlite3_free(err_msg); return rc; } rc = sqlite3_exec(db, "PRAGMA journal_mode = DELETE;", NULL, NULL, &err_msg); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot delete journal file: %s\n", err_msg); sqlite3_free(err_msg); return rc; } return SQLITE_OK; } int main(int argc, char* argv[]) { sqlite3 *db; char *err_msg = 0; int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } // 注册wal_hook函数 rc = sqlite3_wal_hook(db, wal_hook, NULL); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot register wal_hook: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return 1; } // 执行一些操作,使得journal文件被创建 rc = sqlite3_exec(db, "CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT);", NULL, NULL, &err_msg); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot create table: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return 1; } // 进行检查点操作 rc = sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_PASSIVE, NULL, NULL); if (rc != SQLITE_OK) { fprintf(stderr, "WAL checkpoint failed: %s\n", sqlite3_errmsg(db)); } else { printf("WAL checkpoint completed successfully.\n"); } sqlite3_close(db); return 0; } ``` 该示例中,我们注册了一个`wal_hook`函数,在该函数中进行journal文件的检查和清除操作。在主函数中,我们创建了一个表来触发journal文件的创建,然后通过`sqlite3_wal_checkpoint_v2`函数进行检查点操作。在执行完检查点操作后,journal文件将被清除。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值