试图破解SQLite3并发写作的方法,还有更好的方法吗?

时间:2013-01-05 23:57:18

标签: delphi sqlite delphi-xe2 acid

我使用 Delphi XE2 以及 DISQLite v3 (基本上是 SQLite3 的端口)。我喜欢SQLite3的所有内容,除了 缺少并发写作之外,尤其是我在这个项目中广泛依赖多线程:(

我的个人资料表明我需要对此做些什么,所以我决定使用这种方法:

  1. 每当我需要在DB中插入记录时,我会write在一个特殊的填充程序中WriteToFile_Inline(SPECIAL_FOLDER_PATH + '\' + GUID, FileName + '|' + IntToStr(ID) + '|' + Hash + '|' + FloatToStr(ModifDate) + '|' + ...); SQL查询,而不是执行INSERT,即

    timer

  2. 我添加了SPECIAL_FOLDER_PATH(在主app线程中)每分钟触发,解析这些文件,然后使用事务插入查询。

    < / LI>
  3. 最后删除这些临时文件。

  4. 结果我喜欢 500%的性能提升 Plus 此技术 ACID ,因为我总是可以在电源故障后扫描{{1}}并执行我找到的INSERT。

    尽管效果很好,但我对使用的方法不太满意(至少可以说是hackish),我一直在想,如果我有一个快速查找访问的泛型 - ,线程安全,ACID列表,这会更清晰(可能更快?)

    所以我的问题是:您对Delphi XE2有什么相同的知识吗?


    PS。我相信你们很多人在阅读上面的代码时会感到震惊并且会在这一点上开始侮辱我!请成为我的客人,但如果您知道更好(即更快)的ACID方法,请分享您的想法

3 个答案:

答案 0 :(得分:5)

您想要将插入内容发送到队列,这将重新排列插入,并通过预处理语句加入它们是非常好的。在主线程或分离的线程中使用计时器取决于您。它将避免任何锁定。

不要忘记使用事务,然后每隔100/1000次插入提交一次。

关于使用SQLite3的高性能,请参阅例如this blog article (and graphic below)

Speed comparison

在此图中,最佳性能(文件关闭)来自:

  • PRAGMA synchronous = OFF
  • 使用预备陈述
  • 在交易中
  • 在WAL模式下(特别是在并发模式下)

您也可以更改页面大小或日记大小,但上述设置最佳。见https://stackoverflow.com/search?q=sqlite3+performance

如果您不想使用后台线程,请确保WAL为ON,准备语句,使用批处理,并重新组合您的进程以尽快释放SQLite3锁。

通过添加客户端 - 服务器层可以实现最佳性能,就像我们为 mORMot 所做的那样。

答案 1 :(得分:3)

使用文件组织了一个具有持久性的异步作业队列。它允许您避免one-by-one并使用batch(记录组)方法来插入记录。比较one-by-onebatch

  • 首先在每个记录的自动提交模式(可能)中工作,第二个将批处理包装到单个事务中,并获得最大的性能提升。
  • 每当您需要插入记录(可能)时,首先准备一个INSERT命令,每批次第二次,并通过值增益获得第二个。

我不认为,SQLite并发性在您的情况下是一个问题(至少不是主要问题)。因为在SQLite中,单个插入的速度相对较快,并发性能问题会导致高工作负载。您可能会使用其他DBMS获得类似的结果,例如Oracle。

要改进batch方法,请考虑以下事项:

  • 考虑将journal_mode设置为WAL并停用shared cache mode
  • 使用后台线程来处理您的队列。而不是固定的时间间隔(1分钟),更频繁地检查SPECIAL_FOLDER_PATH。如果队列的数据超过X Kb,则开始处理。或者使用排队记录和事件的计数来通知线程,队列应该开始处理。
  • 使用multy-record准备INSERT代替单记录INSERT。您可以为100个记录构建一个INSERT,并在一个批处理中处理您的队列数据,但需要100个记录通道。
  • 考虑写入/读取二进制字段值而不是文本值。
  • 考虑使用一组预分配大小的文件。

答案 2 :(得分:1)

sqlite3_busy_timeout效率非常低,因为当它等待的表被解锁时它不会立即返回。

我会尝试创建一个关键部分(TCriticalSection?)来保护每个表。如果在插入行之前输入临界区并在此后立即退出,则将创建比SQLite提供的更好的表锁。

但是,如果不知道您的访问模式,很难说这是否比将一分钟的插入分配到单个事务中更快。