【问题标题】:Performance problems using Squeryl and H2 database for a desktop application将 Squeryl 和 H2 数据库用于桌面应用程序的性能问题
【发布时间】:2012-02-10 12:34:40
【问题描述】:

我有一个桌面应用程序,将其数据保存在本地 H2 数据库中。我正在使用 Squeryl 连接到数据库。

数据库的大小非常小(大约 10kB)。我遇到了严重的性能问题,并且正在进行大量的磁盘 IO。我只是在读取数据库,因此我希望可以缓存完整的数据;我什至将缓存大小设置为某个值(远高于总数据库大小)。我也尝试禁用锁定但没有结果。

我的程序对数据库执行了非常多的小查询;基本上我有一个 Swing TableModel 对每个表条目(每行的每一列)进行查询。我将这些调用中的每一个包装到一个 Squeryl transaction 块中。

我使用 JVisualVM 创建了一个配置文件,我怀疑以下调用树显示了问题。最上面的方法是从我的代码中读取访问权限。

link to JVisualVM screen shot.

问题

我该如何解决这个问题或我做错了什么?不知何故,我希望我应该能够对一个小到可以保存在 1MB 内存以下的数据库进行许多小调用。为什么会发生此磁盘 IO,我该如何避免?

【问题讨论】:

  • 我不知道它为什么这么慢,但问题是,如果你只需要这么小的数据库(最多几 MB)也许你可以在内存中使用 H2 实例(在启动时从 hdd 复制应用程序)?那么你根本不会有磁盘 IO 的问题......
  • @kuki 这基本上是个好主意。虽然我喜欢(罕见的)写访问现在立即在磁盘上;并且无需显式保存所有内容。

标签: database scala h2 squeryl


【解决方案1】:

查看截图,您似乎正在从 TableModel 的 getValueAt() 方法内的 DB 中进行选择(调用堆栈顶部的方法名称 getRowAt() 导致了我的这种假设)。

如果我的假设是正确的,那么这是您的主要问题。 getValueAt() 被 JTable 的 paint() 方法不断调用(可能每秒几次),所以应该尽可能快。

您应该在单个 SQL 查询中获取 JTable 的数据,然后将结果保存在某种数据结构中(例如 ArrayList 或类似的东西)。

我不知道 Squeryl,但我怀疑您是否真的需要将每个 SELECT 包装到一个事务中。从堆栈跟踪看来,这会导致 H2 中的大量写入。您是否尝试在每次不明确打开(和关闭)事务的情况下运行 SELECTs?

【讨论】:

  • 你的假设是正确的。并且在 TableModel 上本地缓存数据是可行的(一旦我将其作为一种解决方法;这是一个可行的解决方案)。但是不做这个缓存更干净,我认为必须有一种方法,所以我不必缓存。对于您的最后一段,我认为这是解决方案,但这是特定于 Squeryl 的,因为事务由 Squeryl 处理。我不知道该怎么做。
  • @ziggystar:从 Swing 的 UI 系统的角度来看,做缓存是更干净的解决方案。由于您无法控制何时 Swing 重新绘制您的组件(或其中的一部分),因此绘制中涉及的任何方法都应该尽可能快。这是创建响应式 Swing 应用程序的关键点之一。
  • 我再次为表模型使用缓存。但是有更多(如果不是很多)数据库访问分散在我的应用程序中。我不想做的是缓存整个数据库。如果我这样做了,我可以在没有数据库的情况下简单地编写所有内容。也许这就是要走的路……
  • @ziggystar:您可以将所有表创建为“内存”表,让 H2 将数据库完全缓存在内存中。
  • 但是我需要在启动时加载所有内容并最终保存所有内容。这对H2来说很简单吗?目前我正在考虑尝试在一个会话中做所有事情并在每次写入后刷新。你认为这能解决我的问题吗?我仍然需要弄清楚如何使用 Squeryl 来做到这一点。
【解决方案2】:

最终解决方案非常简单。我将引用常见问题解答。

延迟关闭数据库

通常,数据库会在与它的最后一个连接关闭时关闭。在某些情况下,这会减慢应用程序的速度,例如当无法保持至少一个连接打开时。可以使用 SQL 语句 SET DB_CLOSE_DELAY <seconds> 延迟或禁用数据库的自动关闭。参数<seconds> 指定在关闭数据库的最后一个连接后保持数据库打开的秒数。以下语句将在最后一个连接关闭后保持数据库打开 10 秒:

SET DB_CLOSE_DELAY 10

-1 表示数据库没有自动关闭。 0 是默认值,表示在关闭最后一个连接时关闭数据库。此设置是永久性的,只能由管理员设置。可以在数据库 URL 中设置值:jdbc:h2:~/test;DB_CLOSE_DELAY=10

【讨论】:

  • 这是 H2 的常见问题吗? Squeryl为什么要关闭连接,连接池呢,能解决问题吗?
  • @Phil 我不知道有哪些不同的策略可以连接到数据库。我怀疑池化是否能解决问题,因为它是事务“太少”的症状,而且我的程序中有一个阶段没有进行数据库交互。我不知道如何告诉 Squeryl 保持会话打开。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
  • 2013-03-14
  • 1970-01-01
  • 1970-01-01
  • 2015-11-20
  • 1970-01-01
相关资源
最近更新 更多