【发布时间】:2013-09-13 09:03:06
【问题描述】:
我已经通过 hibernate 将 h2 (1.3.172) 用于我的应用程序有一段时间了,在解决了一些非 h2 性能问题后,我的性能瓶颈是 h2。我的数据库非常简单,有 10 个表,每个表的卷少于 100,000 条记录,在 h2 功能范围内也是如此,但我认为问题在于多线程。
我实际上是在使用 hibernate/h2 来控制我的应用程序中的内存消耗。我的应用程序使用管道方法处理文件,可以处理的文件数量没有限制,所以如果我将数据存储在内存中,我会很快点击 OutOfMemory。每个文件通常要经过十个处理阶段,每个阶段都有自己的执行器服务,当文件从一个阶段移动到另一个阶段时,它会作为作业添加到相关的执行器服务上。很少有数据存储在内存中,而是在执行器上启动作业时从数据库中检索有关文件的数据,并在作业完成时将数据写回数据库。我们有 10 个执行器,每个执行器都有机器核心大小的线程池,所以在 4 个机器核心上,理论上我们可以随时向数据库发出 40 个请求,但更常见的是少于 10 个。所以我们有很多事务在进行同时主要涉及少量行。
我的应用程序是多线程的,如果我对它运行分析器,我会发现我的线程大部分时间都处于阻塞状态,等待 executeQuery() 或 executeUpdate()。我读到 h2 是单线程的,所以我认为问题是由 h2 同步请求引起的,而不是锁定,但我可能误解了这一点。我已经设置了 MVCC=TRUE 以便 h2 执行行而不是表锁定,但我仍然会偶尔超时 - 是否可以设置一些东西来检查正在使用的锁。
我读到有一个 MULTI_THREADING 选项,但它不能与 MVCC 一起使用,这很遗憾,因为如果我删除 MVCC=TRUE,我觉得我需要这两个选项,这意味着每次我执行插入或操作时 h2 都会锁定表更新,而且因为我只有几张表,所以它们几乎总是被锁定。
所以,我觉得阻塞可能会大大减少,但我不清楚根本问题是什么以及如何进行
测试 这是我的起点,测试用例需要 3 分 14 秒
3:14,FILE_LOCK=SOCKET;MVCC=TRUE;DB_CLOSE_ON_EXIT=FALSE
我尝试了各种组合,例如
3:02,FILE_LOCK=SOCKET;MVCC=TRUE;DB_CLOSE_ON_EXIT=FALSE;LOG=0;CACHE_SIZE=65536;LOCK_MODE=0;
2:56,FILE_LOCK=SOCKET;MVCC=TRUE;DB_CLOSE_ON_EXIT=FALSE;LOG=0;;CACHE_TYPE=SOFT_LRU;LOCK_MODE=0;
1:05,FILE_LOCK=SOCKET;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000
我发现唯一有很大不同的是删除了 MVCC=TRUE 选项,但不幸的是,我的锁定超时次数从几乎为零增加到加载,所以不幸的是,一些所需的处理没有发生,这可能是总时间更快的原因 因为应用程序中的某些阶段没有完成,或者使用 MVCC 会减慢速度。
我尝试使用 MULTI_THREADED=TRUE 但它似乎根本不适合我
关于在多核系统中的使用
我刚刚阅读了 MULTI_THREADED 选项 https://groups.google.com/forum/#!topic/h2-database/VoE3AU7mSuM 的说明
托马斯说
默认为“非多线程”,意味着只能运行一条语句 随时(每个数据库)。周围有一个同步块 运行声明。启用多线程后, 同步语句在会话(连接)上而不是在 数据库对象。
选项是增加并发性,而不是吞吐量。默认 设置通常不是问题,除非您长时间运行 查询。
如果我理解正确,这意味着当禁用时,虽然 h2 可以接受多个连接,但它一次只会处理一个查询,但即使启用它,它也会在查询之间交换中途但实际上仍然只是一次处理一个查询,即它可以开始处理查询1,然后切换到查询2,然后再返回查询1,但永远不会真正使用cpu并行处理查询1和查询2。
因此,在任何一种情况下,尽管在 cpu 之间切换,它在任何时候都只会使用一个 cpu。因此,如果您有一台功能强大的机器,例如 16 个核心,而瓶颈是数据库,那么添加更多核心根本无济于事因为 h2 一次只能使用一个核心?
这似乎是一个真正的限制,我想知道它与 Derby 或任何其他嵌入式 Java 数据库相比如何。
【问题讨论】: