【问题标题】:ResultSet.next very slow only when query contains FIRST_ROWS or ROWNUM restrictionResultSet.next 仅在查询包含 FIRST_ROWS 或 ROWNUM 限制时非常慢
【发布时间】:2012-02-10 07:00:01
【问题描述】:

我使用

执行本机查询
entityManager.createNativeQuery(sqlQuery);
query.setMaxResults(maxResults);

List<Object[]> resultList = query.getResultList();

为了加快查询速度,我想包含FIRST_ROWS(n) 提示或使用WHERE ROWNUM &gt; n 进行限制。

使用检测,我发现OraclePreparedStatement.executeQuery 确实更快,但在EJBQueryImpl.getResultList 上花费了更多时间,导致整体性能非常差。更详细地看,我发现每 10 次调用 ResultSet.next() 所花费的时间大约与 executeQuery 本身()一样长。当我省略查询提示或 ROWNUM 条件时,这种奇怪的行为就会停止,然后每 10 次调用 resultset.next 就比其他的要低一些,但只有 2 毫秒而不是 3 秒。

【问题讨论】:

    标签: java oracle jdbc eclipselink


    【解决方案1】:

    当您包含提示时,您会得到不同的查询计划吗?我的假设是您根据您对问题的描述这样做。

    当您在 Oracle 中执行查询时,数据库通常不会在任何时间点实现整个结果集(显然,如果您指定 ORDER BY 子句要求之前实现所有数据,则可能必须排序发生)。直到客户端开始获取数据,Oracle 才真正开始实现数据。它运行足够的查询来生成客户端要求获取的行数(在您的情况下听起来像是 10 行),将这些结果返回给客户端,并等待客户端请求更多数据,然后再继续处理查询。

    听起来,当包含FIRST_ROWS 提示时,查询计划正在发生变化,导致执行成本更高。显然,这不是FIRST_ROWS 提示的目标。目标是告诉优化器生成一个计划,使获取前 N 行的效率更高,即使它降低了从查询中获取所有行的效率。这往往会导致优化器偏爱诸如索引扫描之类的事情,而不是表扫描,因为表扫描总体上可能更有效。然而,在你的情况下,优化器的估计是不正确的,它最终选择了一个通常效率较低的计划。这通常意味着您的查询引用的某些对象的某些统计信息不完整或不正确。

    【讨论】:

    • 谢谢。我对 n 之后的行不感兴趣,这也是我使用 setmaxresults 的原因。当使用ROWNUM &lt; n 而不是查询提示时,问题也存在,因此应该优化它以返回具有此限制的查询可以返回的所有 n 行。是的,我得到了不同的执行计划,但是在 SQL 开发人员中,例如,返回 n 行非常快,而当与 eclipselink 一起使用时,持续时间似乎乘以 n/10。
    • @stracktracer - 你能发布查询和你得到的各种查询计划吗? SQL Developer 计划是否与 eclipselink 计划相同?默认情况下,SQL Developer 只返回前 50 行数据。您确定要让 SQL Developer 获取所有数据并测量该时间,而不是仅仅测量获取前 50 行所需的时间吗?
    【解决方案2】:

    尝试直接将最大行数限制添加到 SQL 中,而不是使用 setMaxResults,即在 sql 字符串中添加 where rownum

    【讨论】:

      【解决方案3】:

      听起来您使 JDBC executeQuery 更快,但 JDBC ResultSet 下一个更慢。您使查询的执行速度更快,但获取数据的速度更慢。似乎是 JDBC 问题,而不是 EclipseLink,如果您实际获取数据,您将通过原始 JDBC 获得相同的结果。

      10 是默认提取大小,因此您可以尝试将其设置为更大。

      看, http://www.eclipse.org/eclipselink/api/2.3/org/eclipse/persistence/config/QueryHints.html#JDBC_FETCH_SIZE

      【讨论】:

      • 增加了获取大小。现在nexts 的速度变慢了,但不幸的是,其余的会按比例变长,因此总持续时间不会受到影响。如果我将提取大小设置为与 ROWNUM 数一样高,则只有 executeQuery 需要很长时间。
      猜你喜欢
      • 2014-02-18
      • 2016-06-09
      • 2022-10-19
      • 2014-06-01
      • 2016-12-22
      • 1970-01-01
      • 2015-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多