内存测试数据库
2005年11月22日
内存数据库是在主内存中完全运行的数据库,不接触磁盘。它们通常作为嵌入式数据库运行:在进程启动时创建,嵌入在该进程中运行,并在进程结束时销毁。
虽然大多数人认为数据库是大型以磁盘为中心的实体,但实际上存在着一个小型但繁忙的内存数据库世界。有些应用程序需要快速访问某种管理数据,而这些数据不需要持久化,因为它们不会改变,或者可以重建(想象一下路由器中的路由表,或者一个EventPoster)。
即使是传统数据库系统的开发人员也会发现内存数据库很有用,尤其是在测试方面。在开发企业应用程序时,访问数据库的测试在运行测试套件时会占用大量时间。切换到内存数据库可以带来数量级的性能提升,从而显著减少构建时间。由于大多数ThoughtWorkers如果没有最近的绿色构建就会感到不安,因此这对我们来说意义重大。
人们似乎采取两种途径来使用内存数据库进行测试。第一种是使用 SQL 内存数据库库。在 Java 世界中,流行的库似乎是HSQLDB。在其他地方,SQLite和Firebird也很常见。这些工具的优点是它们允许你使用常规 SQL 查询它们。一个问题是它们可能不支持完全相同的方言或目标数据库的所有功能。你可以通过在 RAM 磁盘上运行基于文件的数据库来做类似的事情,这使你能够使测试和生产部署更接近彼此。
另一种途径是将所有数据库访问抽象到一个Repository后面。然后你可以用常规的内存数据结构替换数据库。通常,对于对象图的入口点,只需要一堆哈希表就足够了。Repository 方法的优点之一是它为你提供了一种一致的方式来访问(和存根)非 SQL 数据源。这意味着你的对象关系映射系统也被隐藏在 Repository 内部。
事实上,有些人积极地不喜欢使用 SQL 内存数据库,因为他们认为这会鼓励在域模型中传播 SQL 或对象关系映射代码。在内存中运行 SQL 可能会消除缓慢访问的大部分痛苦,但它就像除臭剂一样,掩盖了缺少 Repository 的气味。
到目前为止,测试是主要驱动力,但我认为内存数据库还有更多潜力。现在的内存大小足以容纳许多应用程序数据库。如果你使用一种方法来保存应用程序状态的所有更改的事件日志,你可以将内存数据库视为应用日志结果的缓存,并在需要时重建和快照它。这种风格在有大量读取者和少量写入者的场景中可以非常可扩展且具有高性能。我遇到过一些案例,人们使用内存数据库来构建高性能应用程序。这里的一个区别是,这些经验往往与利基商业数据库有关,而对于测试,人们似乎更喜欢开源数据库。
Prevayler因采用这种方法而备受关注。我认识的一些尝试过它的人发现,它与内存对象的紧密耦合以及缺乏迁移工具导致了严重的问题。但我认为,将持久性更改日志作为记录系统的方法是未来值得探索的沃土。
后续
在写完这篇文章后,我收到了一些有趣的邮件,所以我想分享一些观点。
一位通信者说,他喜欢使用内存数据库来完成 SQL 做得很好而对象做得不好的任务。当然,在某些情况下,SQL 可以比对象或过程代码更优雅地解决问题,尽管通常我发现只有少数开发人员喜欢用 SQL 思考。
我的同事 Steve Sparks 告诉我一个最近的项目,在测试中,他们会在第一次调用时从实时数据库中提取数据,然后将这些数据保存到一个文件中,以初始化内存 Repository,这样后续查询就不会访问数据库。我第一次看到这种做法是在 C3 项目中,它将数据保存在一个以 SQL 查询字符串为键的哈希表中。如果没有值,它会去 DB2 并缓存结果。
Steven Graves 指出,我最初的条目并没有真正谈论内存数据库的通用用途,因此我进行了一些改写,并重新命名了该条目。
(感谢 Peter Becker、Zane Rockenbaugh 和 Steve Sparks 对我的评论。我还应该感谢我们内部邮件列表中未指明的 ThoughtWorkers 的宝贵意见。