7

我正在查看一个非常慢的 SQL 查询(源自使用 JBoss 5.1 中部署的 Hibernate 的 Java 应用程序)。这个特定的查询返回了大约 10K 条记录,但仍然需要 40 秒或更长时间。

我最终用数据库嗅探了流量(wireshark 有一个用于 TNS 的解析器)并发现了一些意想不到的东西。当数据来自服务器时,每个结果行都在其自己的 TNS 数据包中。此外,在从数据库发送下一个 TNS 数据包之前,客户端(即应用服务器)会确认每个 TNS 数据包。对于 10K 记录,有 10K 往返来获取数据包并确认它。对性能的影响是巨大的。

这是非常低效的。TCP 允许更大的数据包并具有许多机制(滑动窗口、延迟的 ACK)来减少延迟并增加吞吐量。但是,在这种情况下,是顶部的 TNS 协议添加了自己的协商。

如果我从 Oracle 的 SQL Developer 运行相同的查询,我看不到这种模式。查询在大约 1/10 的时间内完成,无需数千次往返。

简短版本:Oracle 的有线协议 (TNS) 似乎在每个查询结果行一个 TNS 数据包中传递数据,并要求客户端在服务器发送下一个数据包之前确认每个数据包。

我在 [这里][1] 找到了一些关于此的信息(向下滚动到“tnsnames.ora 文件中的 SDU 和 TDU 参数”部分)。

因此我的问题是:是否可以控制 Oracle 驱动程序的行为(我使用的是 10.2.0.4.0)以使 TNS 协议更有效?同样,这是部署在 JBoss 中的非常标准的 J2EE 应用程序。

非常感谢!

4

2 回答 2

6

调整tnsnames.ora 和 listener.ora 中的SDUTDU参数

将当前语句的批量大小设置为 100。

  ((OracleStatement)stmt).setRowPrefetch (100);

笔记:

设置预取大小会影响应用程序的性能。增加预取大小将减少获取所有数据所需的往返次数,但会增加内存使用量。这将取决于查询中列的数量和大小以及预期返回的行数。它还取决于 JDBC 客户端机器的内存和 CPU 负载。独立客户端应用程序的最佳性能与负载很重的应用程序服务器不同。网络连接的速度和延迟也应该考虑连接也应该考虑

(来自Oracle Database JDBC Developer's Guide and Reference

此处可用的连接属性。

也看看Oracle UCP

于 2010-10-08T20:27:25.457 回答
3

尝试增加您的状态对象的获取大小。

我认为默认值为 10,因此您可以尝试从 100 开始。

语句 stmt = connection.createStatement();
stmt.setFetchSize(100);
结果集 rs = stmt.executeQuery("SELECT ...");
于 2010-10-08T20:09:28.660 回答