我一直在研究只读与读写数据库事务的性能。 MySQL服务器在慢速VPN链接上是远程的,因此我很容易看到事务类型之间的差异。这是连接池,我知道它基于比较第一次和第二次JDBC调用。
当我将Spring AOP配置为在我的DAO调用上使用只读事务时,与读写相比,调用速度慢30-40%:
<!-- slower -->
<tx:method name="find*" read-only="true" propagation="REQUIRED" />
...
// slower
@Transaction(readOnly = true)
与:
<!-- faster -->
<tx:method name="find*" read-only="false" propagation="REQUIRED" />
...
// faster
@Transaction
看看tcpdump,似乎只读事务在与MySQL交谈时做得更多。这是read-only dump与read-write。
非常感谢。
为什么spring / hibernate只读数据库事务比读写运行慢?
好的,这是一个有趣的旅程。很多我可以学习和分享。下面的一些应该是显而易见的,但希望我的无知和我所学到的将有助于其他人。
<tldr>对问题#1的简短回答是,hibernate使用@Transaction(readOnly = true)
同步JDBC调用从set session.transaction.read.only
会话开始,并以set session.transaction.read.write
调用结束。执行读写调用时不会发送这些调用,这就是为什么只读调用较慢的原因。
对问题#2的更长答案涉及我尝试降低远程数据库性能的步骤的以下详细信息:
; Got these from: https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux
proto udp
tun-mtu 6000
fragment 0
mssfix 0
tcpdump ... -X
),我注意到有很多不必要的自动提交和只读/读写JDBC调用。升级到我们使用的更好版本的真棒HikariCP connection pool库有助于此。在版本2.4.1中,他们添加了一些智能,减少了一些这些调用。只读事务开销低至120ms。读写仍然是100ms。尼斯。jdbc:mysql://.../database?useLocalSessionState=true&useLocalTransactionState=true
这些设置导致删除了更多的同步JDBC命令。只读事务开销降至60ms,现在与读写相同。呜呜。
编辑/警告:在发现驱动程序未发送交易信息的错误后,我们实际上回滚添加useLocalTransactionState=true
。connection.setReadOnly(true)
,它会从特殊池中发出连接。
使用此自定义池将只读和读写连接的事务开销降低到20ms。我认为它基本上删除了最后一个JDBC事务开销调用。以下是我主页上two classes that I wrote的来源。代码相对脆弱,依赖于Hibernate做connection.setReadOnly(true)
的第一件事,但它似乎运行良好,我在XML和代码中仔细记录它。因此,在几天的工作中,基本的@Transaction
开销从480毫秒增加到20毫秒。对于dao.find(...)
方法的100“真实生活”休眠调用在55秒开始并以4.5秒结束。漂亮踢屁股。希望速度提高10倍总是很容易。
希望我的经验可以帮助他人