1

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

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

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

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

链接到 JVisualVM 屏幕截图。

问题

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

4

2 回答 2

3

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

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

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

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

于 2012-01-14T21:55:26.923 回答
1

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

延迟数据库关闭

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

SET DB_CLOSE_DELAY 10

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

于 2012-01-16T21:27:54.927 回答