处理多进程访问的SQLite最佳实践[已关闭]

siv3szwd  于 2023-03-03  发布在  SQLite
关注(0)|答案(1)|浏览(328)
    • 已关闭**。此问题为opinion-based。当前不接受答案。
    • 想要改进此问题吗?**请更新此问题,以便editing this post可以用事实和引文来回答。

6天前关闭。
社区在4天前审查了是否重新讨论此问题,并将其关闭:
原始关闭原因未解决
Improve this question
我们有一个单一的SQLite数据库,可供许多(~20)进程在Windows上从C++和C#访问。该数据库以WAL模式打开。
每个进程打开数据库一次,然后每秒执行几次连续的读和读/写事务。每个事务都很短:一次选择查询、一次插入或一次覆盖(先删除后插入)。我们在一个单独的事务中执行每个操作。
这些查询的所有相关字段和组合都具有相关索引。
我们观察到相当差的性能,我们需要大量的重试来克服SQL_BUSY-我们达到了10000次重试,每次之后是1 - 10毫秒的随机休眠,我们有时需要数千次重试才能通过查询。(注意,运行此操作的服务器通常会非常繁忙)。
我们还观察到WAL文件变得越来越大--有时候会达到千兆字节的大小。为了解决这个问题,我们每小时运行一次PRAGMA wal_checkpoint(TRUNCATE),然后再运行VACUUM并删除旧条目。数据库文件本身保持相当稳定(约100MB)。
我们在这里做错了什么吗?或者有什么方法可以提高性能吗?我们应该为每个事务打开和关闭一个数据库吗?或者我们可以尝试其他方法吗?

w3nuxt5m

w3nuxt5m1#

我看到不同的问题,我会一次面对一个。

1.处理SQL_忙碌

我假设您正在处理代码中的错误,等待并重试。您可以尝试让SQLite库处理重试,方法是在连接开始时设置PRAGMA busy_timeout = milliseconds;

2.管理文件大小

WAL文件不会自动收缩,因为覆盖它比追加它快。您可以设置PRAGMA journal_size_limit = N;来保持它在可管理的大小,而不是截断它。请在此处添加文档。还要注意,VACUUM确实会生成较大的WAL大小,因此在截短WAL文件之后立即清空数据库将部分地否定该截短。也许在设置PRAGMA journal_size_limit之后,您会发现数据库每天只能进行一次真空处理。

3.提高并发性

由于在WAL模式下,许多读取器和一个写入器可以并发运行,因此冲突来自多个并发写入器。因此,您应该尽可能地降低写入速度并使写入速度尽可能快。您可以尝试的第一件事是在连接开始时设置PRAGMA synchronous = NORMAL。这应该允许更快的写入,而不会有损坏数据库的风险(请参阅此处)。
之后,您可以查看数据库中的索引。(插入、删除或更新)将不仅需要写入表的相应页,而且还需要写入为该表定义的每个索引的修改页。检查是否存在不必要且可以删除的索引。可能您添加其中一些索引是为了加快某些SELECT查询的速度,但如果必须等待100毫秒才能完成写事务,则将查询从10毫秒加速到5毫秒是没有意义的。最好将其保持在10毫秒,并使写事务在80毫秒内完成。
所有这些建议都应该很容易测试,只需对你的代码稍作修改。如果它不起作用,那么你可能需要对你的实现做更大的修改。在这种情况下,你会发现切换到不同的RDBMS,如mason所建议的,可能会更容易。

相关问题