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

正如此处详述并在 此处确认的那样,Oracle在通过JDBC查询数据时返回的默认行数是10.我正在开发一个必须读取和比较数据库中大量数据的应用程序。 我认为如果我们只是将defaultRowPrefetch增加到类似于1000的东西,那么我们的应用程序肯定会更快。 事实certificate,它的表现较慢 ,约为20%。

然后,我们决定从10开始慢慢增加数字,看看它的表现如何。 通过将它设置在100到200之间我们已经看到了大约10%的增长。但是,我绝不会猜到,将它设置得更高会使我们的应用程序执行得更慢。 任何想法为什么会这样?

谢谢!

编辑:

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

编辑2:

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

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

所有其他事情都是平等的,正如我们在测试中所做的那样,我们非常好奇我们的应用程序只有这一次变化才能表现得更差。

可能的解释:

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

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

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

  4. 如果获取过程与其他Java代码同步,则会变得更糟,因此Java只在处理完之前的数据后才会请求更多行,而Oracle同时不做任何事情。

    想象一下有3个人:

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

    堆栈有多大,如果第一个必须等​​到第二个返回而第二个必须等到第三个完成它们的工作?

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

与所有内容一样,没有FAST=TRUE设置。 虽然JDBC的默认提取大小为10并不适合您的情况,但对于“典型”OLTP应用程序来说是可以的,对您的情况来说,这似乎也不是那么糟糕。 显然,大的提取大小也不适合您的情况。 但同样,一次完成1000并不是那么糟糕。

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

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

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

正确的方法是使用setFetchSize。

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

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

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

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

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

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

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

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

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

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

daveslab,更多信息……

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

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

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

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

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

我希望你明白,我正在使用谷歌翻译。