(在WAL模式下使用Delphi 2010+最新SQLite)
我正在将DISQLite(SQLite的Delphi端口)与我的多线程客户端应用程序(尚未发布,因此如果我真的必须更改DB引擎)
我的探查器清楚地说这是一个愚蠢的决定,我把它追溯到了2-3个非常简单的SQL语句,当在单线程应用程序中执行时,这些语句会飞起来,但因为线程锁定/等待(SQLite在多个线程试图同时写的情况下确实表现不佳)
我尽了最大努力优化我的代码/避免瓶颈,但经过几周的努力,我现在想知道转储SQLite&选择不同的数据库引擎(?)
我的要求是:
- 酸
- 非常好的同时读/写(记录级别)支持
- (非常)快速;稳定DB引擎
- B-树
- Delphi 2010支持
我只使用带索引的基本INSERT/UPDATE/DELETE命令,没有什么特别之处。因此,我的SQL需求是相对基本的(我不需要联接或其他"更高级"的SQL内容)。
我也对NQL解决方案持开放态度,只要它支持上述要求。
我的研究引出了Berkley DB,如果我理解正确的话,它是一个具有并发写作支持的SQLite的修改版本,但问题是它并不适用于delphi。
我也读过关于京都内阁的文章,但话说回来,没有delphi支持:(
任何建议都非常受欢迎,
谢谢!
如果:,您的应用程序速度是多少
- 所有线程只使用一个DB连接
- 您可以使用全局关键部分来保护数据库连接访问
然后你可以尝试我们的Sqlite3静态绑定,它是在没有线程互斥的情况下编译的:
#define SQLITE_THREADSAFE 2
// assuming multi-thread safety is made by caller - in our framework, there is
// only one thread using the database connection at the same time, but there could
// be multiple database connection at the same time (previous was 0 could be unsafe)
#define SQLITE_OMIT_SHARED_CACHE 1
// no need of shared cache in a threadsafe calling model
我们在我们的mORMotORM框架中使用了这样一个模型,并与四个级别的缓存相关联:
- 用于SQL语句重用的语句缓存,以及动态绑定参数
- 数据库级别的全局JSON结果缓存,在任何INSERT/UPDATE上全局刷新
- 为服务器端的指定表或记录在CRUD/RESTful级别上调整的记录缓存
- 为客户端上的指定表或记录在CRUD/RESTful级别调整的记录缓存
由此产生的性能一点也不差——它在多线程访问中可以很好地扩展,即使有全局关键部分也是如此。当然,SQlite3的扩展能力并不如Oracle!但我在实际应用程序中使用过SQlite,有很多客户端。您可以考虑使用FireBird,它为客户端服务器提供了更复杂(经过调优)的体系结构。
关于让写作更快,你可以将你的写作分组到一个事务中,然后它会更快这就是我用于加速写入的方法,您可以将这一概念扩展到多个客户端:在服务器端,您将写入重新组合为一个共享事务,该事务将在超时期(例如一秒钟)后提交。
SQLite3对于这样的添加来说非常快(使用带有绑定参数的准备好的INSERT语句更是如此),但对于单个添加来说速度很慢,因为它必须使用低级API锁定整个文件,这非常慢。为了使其成为ACID,请确保始终处理提交。事实上,其他数据库引擎通过隐藏在后台的类似进程实现了良好的并发速度。SQLite3默认的编写方法应该是这样的,以确保从多个进程访问同一个文件-但在客户机-服务器应用程序中,您可以依赖这样一个事实,即您将是唯一一个访问SQLite3数据库文件的人,因此它是安全的。
像Firebird DB的嵌入式版本有什么帮助吗?
FirbirdSQL.org下载页面
我过去曾成功地使用过这个。
只需将表(可以同时写入)拆分为单独的SQLite数据库文件,并使用主连接将它们连接在一起。
FWIW,我最终决定坚持使用DISQLite以及这个"丑陋"、黑客化的解决方案:
-
做了一些(不太小的)更改,以尽可能减少线程内对数据库的写入(每个线程需要插入两个数据库)
-
当我在线程内工作时,必须向DB写入一些东西时,我使用了SQL查询参数&将它们写在一个特殊的文件夹中(写入文件非常快),即
C: \我的项目\挂起的sql\insert_SOME-GUID.txt
每个文件看起来像这样:
Param1|Param2|Param3|Param4|
-
一旦我处理完线程(或者如果我的应用程序崩溃),我就会调用一个例程来扫描这个文件夹,提取SQL参数,并使用准备好的语句(封装在事务中)运行它们。
-
任何包含少于4个参数的文件都将被视为已损坏,并将被跳过。
这是一个非常糟糕的算法(我真遗憾!),但它很有效,速度很快,有点像ACID,我不必花几个月的时间学习另一个可能合适(也可能不合适)的DB引擎。
我只是想感谢大家的帮助,时间压力让我无法切换到另一个DB引擎,至少在这个项目中是这样。
这是我的观点:
绝对数据库是一个不错的选择。
NexusDB可以做到这一切,嵌入式版本是免费的。它支持德尔福成为一等公民。