设置Oracle大小的行提取更高使我的应用程序更慢?

时间:2012-02-09 22:51:50

标签: java performance oracle jdbc oracle11g

详细here并确认here,Oracle在通过JDBC查询数据时返回的默认行数是10.我正在开发一个必须阅读和比较批量的应用程序我们数据库中的数据。我认为,如果我们只是将defaultRowPrefetch增加到像1000这样的东西,那么我们的应用程序肯定会表现得更快。事实证明,执行速度较慢约为20%。

然后我们决定从10开始慢慢增加数字,看看它是如何表现的。我们已经看到将其设置在100到200之间,大约增加了10%。但是,我绝不会猜到,将它设置得更高会使我们的应用程序执行速度变慢。有什么想法可能会发生吗?

谢谢!

修改

为了澄清,我使用的是Oracle 11g R2和Java 6.

编辑2:

好的,我想重申一下我的问题,因为从下面的答案来看,我并没有正确表达自己:

  

如果我设置更高的提取大小,我的应用程序执行速度有多快?对我来说,这听起来像是在说“我们给你一个更快的互联网连接,即一个更胖的管道,但你的网页浏览会更慢。

所有其他事情都是平等的,正如我们在测试中所做的那样,我们对于我们的应用程序如何只通过这一次更改而表现更差感到非常好奇。

6 个答案:

答案 0 :(得分:23)

可能的解释:

  1. Java无所事事,而Oracle正在计算前1000行而不是前10行。

  2. Oracle无所事事,而Java正在计算最后1000行而不是最后10行。

  3. 通信协议(例如TCP / IP)等待很多,然后必须一次处理更多数据,但峰值数据传输将受到硬件限制的限制。这可以通过协议的开销来抵消,因此应该有最佳的提取大小,任何更少或更多的东西都会更慢;))

  4. 如果获取过程与其他Java代码同步,情况会变得更糟,因此 Java只在处理完之前的数据后才会要求更多行,并且Oracle同时不执行任何操作

      

    想象一下有3个人:

         
        
    • 第一张将A4纸折成两半
    •   
    • 第二个将一叠折叠纸从一个房间带到另一个房间
    •   
    • 3rd从折叠纸上剪下一些形状。
    •   
         

    筹码有多大,如果第一个必须等​​到第二个回归而第二个必须等到第三个完成他们的工作?

         

    1000的堆栈不会比10的堆栈更好我猜;))

答案 1 :(得分:12)

与所有内容一样,没有FAST=TRUE设置。虽然JDBC默认提取大小为10并不适合您的情况,但对于“典型”OLTP应用程序来说是可以的,并且看起来确实不是 对您的情况有害。显然,大的提取大小也不适合您的情况。但同样,

您未提及的另一个因素是 WIDE 是如何拉动行的。请考虑通过网络从数据库服务器提取到应用服务器的数据块是sum(WIDTH*ROWS)。如果你的行是5000字节,并且你一次拉1000,那么每次获取将带来5 MB的数据。在另一种情况下,也许你的行只有100个字节的“瘦”。然后取出其中1000个只穿梭100K左右。

因为只有您可以知道回来的数据是什么样的,所以建议在系统范围内为“常规”情况设置提取大小,然后根据需要单独调整奇怪的查询。

一般来说,我也发现100是大数据流程的更好设置。这不是推荐,而是转发观察。

答案 2 :(得分:6)

The correct method将使用setFetchSize。

  

默认情况下,当Oracle JDBC运行查询时,它会检索结果集   从数据库游标一次10行。这是默认值   Oracle行获取大小值。您可以更改行数   通过更改行检索每次数据库游标   获取大小值。

     

标准JDBC还允许您指定提取的行数   每个数据库往返查询,并引用此数字   作为获取大小。在Oracle JDBC中,使用行预取值   作为语句对象中的默认提取大小。设置提取   size会覆盖row-prefetch设置并影响后续查询   运行该语句对象。

     

获取大小也用于结果集。当语句对象运行时   一个查询,将语句对象的获取大小传递给   查询生成的结果集对象。但是,您也可以设置   获取结果集对象中的大小以覆盖语句提取   传递给它的大小。

答案 3 :(得分:6)

BTW,至少对于Oracle,您需要小心提取大小,因为Oracle驱动程序会为每行占用最大可能大小的数组而不是实际数据大小。因此,如果你有一个胖桌子,你的内存占用可能会受到影响。

看看这里 - http://www.oracle.com/technetwork/database/enterprise-edition/memory.pdf

在Oracle中,您可以找到user_tab_columns元数据表(data_length)中列的最大可能空间。它可用于确定提取大小。

在粗略测试中,我发现4 * 1024 * 1024 / sum(表的所有列的data_length)是合理的提取大小。

答案 4 :(得分:1)

几乎就是亚当H.所说的 - 对于每种类型的场景都没有通用的设置。 Oracle需要一段时间来获取行,因此在将服务器端发送到客户端之前等待服务器上的行所花费的时间,如果将预取阈值设置得更低,则可能已经花费在应用程序中,因此性能会受到影响。

据我所知,Oracle还使用客户端缓存来提供可滚动游标。它可以帮助将光标设置为仅向前,至少从内存预期。至少它曾经在旧版本的JDBC驱动程序中有所帮助,也许从那以后行为发生了变化。

Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY);

答案 5 :(得分:1)

daveslab,更多信息......

如果您的应用程序需要整个结果集来开始处理数据,则较大的提取大小可以带来改进。但是,没有神奇的数字,有必要测试最有益的价值。

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

Oracle JDBC客户端似乎预先初始化了一些内存结构以保持完整的预取大小。因此,如果您将预取大小设置为500,则分配大量内存的时间比预取大小= 10时要多。这对GC来说是一个巨大的额外需求,特别是如果您实际上没有读取那些行。要想一想,你可能正在运行GC 50x,如果你通常只需要获取几行,那么通常需要更多。这将对您的应用程序响应性产生重大影响。

如果可能,我建议在每个查询的基础上使用setFetchSize。例如,如果您知道某个特定查询只返回几行,则将获取大小设置为5.如果您知道查询将返回1000行,则使用提取大小为100。

作为一种启发式方法,超过50-100的收益有限。

我希望您理解,我使用谷歌翻译。