Java ResultSet.next()对于oracle引用游标来说太慢

Java ResultSet.next()对于oracle引用游标来说太慢,java,oracle,jdbc,resultset,slowdown,Java,Oracle,Jdbc,Resultset,Slowdown,我从java调用一个oracle过程,它返回一个ref游标作为结果。我将ref光标投射到一个ResultSet,迭代从它开始 String query = "{call ...(...)}"; CallableStatement stmt = conn.prepareCall(query,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); stmt.setFetchSize(10000); . .

我从java调用一个oracle过程,它返回一个ref游标作为结果。我将ref光标投射到一个ResultSet,迭代从它开始

String query = "{call ...(...)}";
CallableStatement stmt = conn.prepareCall(query,ResultSet.TYPE_FORWARD_ONLY,
                ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(10000); 
.
.
.
stmt.registerOutParameter(x, OracleTypes.CURSOR);
stmt.execute();
Resultset rs = (ResultSet) stmt.getObject(x);

while (rs.next()) {    /** Problem occurs here **/
    ...
}
问题是,有时对于某些特定记录,ResultSet.next方法花费的时间太长,比如100秒。需要指出的是,返回的记录最多为25条,数据库中的同一查询通常在6秒内执行

随着我的进一步调查,我发现在返回的游标中有一列,如果删除该列,则不会出现此问题。该列实际上是结果游标中包含的ROWNUM

--ORACLE Query snippet:
OPEN result_cursor FOR 
SELECT "FirstName","LastName", r 
  FROM (SELECT ROWNUM r, *
         ... -- query details
         WHERE ROWNUM <= 25)
我甚至没有触及结果集中的那个字段,但它仍然会导致这个看起来不公平的问题:。在Oracle过程中,我尝试通过将其与“”连接,将其转换为字符串,假设类型转换可能会导致此问题,但在这种情况下没有任何区别。
为什么会发生这种情况?

您正在谈论的字段ROWNUM是一个可变值,因为可能会插入行,这实际上可能会改变绝对行号,在执行提取操作时需要重新计算绝对行号,说明自上次fetch调用以来游标返回的表中的任何插入或删除。每次调用rs.next都会导致一个fetch操作,因为此列是一个可变的值,即使您很快就能得到其余的结果


之所以会出现这种情况,是因为在导航结果集时,使用ref光标会使SELECT保持打开状态。

将获取大小设置得如此之高是在浪费内存,我认为设置和拆除结构可能需要相当长的时间。您是将r从最终选择列表中排除,还是删除rownum@AlexPoole:我已将fetch size设置为不同的值10、25、。。。这也没什么区别。我只是将r从最终的select列表中排除,查询主体保持不变。我觉得ref cursor到ResultSet的转换导致了这个问题,但我找不到原因;如果您使用的是10g,我想知道绑定变量窥视,特别是在它是间歇性的情况下。是否可以使用相同的绑定值检查两个查询的执行计划?在会话上运行oracle跟踪,并在会话上运行tkprof。我在外部oracle SP中调用SP之前和之后都进行了日志记录,日志时间显示SP已在适当的时间在DB级别执行。另外,正如我所说的,当从像navicat这样的db客户端调用SP时,不会发生这种情况。我在navicat中获取光标并对其进行迭代,一切正常,没有人受伤。但java中使用JDBC的相同SP调用导致了上述问题。因此,这似乎不是执行计划DB端的问题。但我还是会按照你的建议来寻找进一步的线索。这是有道理的,但解决办法是什么呢?尝试将结果选择到临时表中,然后在临时表上打开光标。或者只返回一个正常的结果集而不是光标。