【问题标题】:JPA query extremely slow when setMaxResults is set设置 setMaxResults 时 JPA 查询非常慢
【发布时间】:2023-04-08 11:26:01
【问题描述】:

在一个特定的项目中,我遇到了不同配置下的类型化查询问题。

当在 TypedQuery 上设置的 maxResults 值大于查询返回的实际结果数时,getResultList() 需要很长时间才能执行(有时最多需要 350 秒才能检索由 6 列组成的 10 行)。

相比之下,没有 setMaxResults 的相同查询需要大约 15 秒才能执行。更改WHERE 参数以检索更多结果的相同查询也非常快。

我正在使用本地资源数据源的 Junit 测试类中测试所有这些,但是 Weblogic 10.3.6(以及 Jboss EAP 6.1)上的 JTA 数据源也会发生同样的情况,但我认为不是相关)。

我尝试在persistence.xml中使用hibernate.jdbc.fetch_sizehibernate.jdbc.wrap_result_sets,但很难估计是否有改进:一旦查询成功并被Oracle缓存,执行速度会很快无论我如何调整这些值(我没有权限清除 Oracle 的语句缓存)。

我注意到,如果我从查询中删除 ORDER BY,执行时间会下降到 50-60 秒,这仍然太长但仍不到 350 秒。不过,该列已编入索引(它是主键),因此我不明白为什么它会对性能产生如此大的影响。

我正在使用 Criteria API 构建查询,但我也尝试使用 HQL 或本机 SQL。我使用CriteriaQuery#multiSelect 仅检索所需的字段,然后将结果分配给具有适当构造函数的类 (select new ...)。

这是由 Hibernate 翻译的查询:

SELECT * FROM
  (SELECT message0_.MESG_ID  AS col_0_0_,
    message0_.CREATION_DATE  AS col_1_0_,
    messagetyp1_.MSGT_ID     AS col_2_0_,
    message0_.MESSAGE_NAME   AS col_3_0_,
    interview2_.INVW_ID      AS col_4_0_,
    interview2_.IVWT_ID      AS col_5_0_,
    party3_.LICENSE_USERNAME AS col_6_0_
  FROM  message0_
  LEFT OUTER JOIN S399_MESSAGE_TYPES messagetyp1_
  ON message0_.MSGT_ID=messagetyp1_.MSGT_ID
  LEFT OUTER JOIN S399_INTERVIEWS interview2_
  ON message0_.INVW_ID=interview2_.INVW_ID
  LEFT OUTER JOIN S399_PARTIES party3_
  ON message0_.PRTY_ID          =party3_.PRTY_ID
  WHERE message0_.CREATION_DATE>=?
  AND (interview2_.IS_POLLING  IS NULL
  OR interview2_.IS_POLLING     =0)
  ORDER BY message0_.MESG_ID DESC
  )
WHERE rownum <= ?

当我在 SQLDeveloper 中运行它时,它很快(应该如此),通常不到一秒。

当我调试 Hibernate 的代码时,我可以看到在 ps.executeQuery() 上异常缓慢的是 org.hibernate.jdbc.AbstractBatcher.getResultSet(PreparedStatement)。它应该指向我的 JDBC 驱动程序问题还是数据库问题?

提前感谢您对这种情况的任何建议或想法。

配置:

  • Java 6
  • Hibernate 3.6.10 (JPA 2.0)(尝试升级到 Hibernate 4 和 JPA 2.1,没有变化)
  • Oracle 数据库 11g (11.1.0.7.0)
  • Oracle jdbc 驱动程序 11.2.0.3(用 11.1.0.7.0 和 11.2.0.4 试过,没有变化)。
  • hibernate.dialect:Oracle10gDialect。

可能重复:ResultSet.next very slow only when query contains FIRST_ROWS or ROWNUM restriction

【问题讨论】:

    标签: java sql oracle hibernate jpa


    【解决方案1】:

    您可以尝试添加/*+ FIRST_ROWS */ 提示。如果它没有帮助,您将不得不找出 Hibernate 实际执行的内容。

    更新:您的查询需要查看多少数据(以 MB 为单位)? 15 秒的响应时间是否合理?您能否提供该查询的“解释计划”?

    查看查询,您似乎应该在message0_.CREATION_DATE 上有一个索引。您可以尝试在 where 子句中提供上限。就像 Tom Kytes 经常说的那样……想想吧!如果您在过去和现在的某个日期之间查询数据,并且您没有传入上限 (SYSTIMESTAMP) - 您基本上希望数据库能够走很长一段路才能知道在日期列。 Oracle 会执行“绑定参数窥视”之类的操作 - 它甚至会查看您提供的边界的实际,如果它认为成本更低,它可能会决定不同的查询计划。 ...

    您知道 ORDER BY 是在 where 子句之后计算的吗?这意味着,您不会根据您的 order by 获得前 n 条记录,而是获得 n 条随机记录,然后再进行排序....

    【讨论】:

    • 我想尽量避免使用提示,因为 Hibernate 不支持它们。此外,当您说在这种情况下在 where 子句之后评估 ORDER BY 时,我认为您错了,因为我的查询使用子查询 (select * from (...) where rownum &lt;= ?)。看这篇经常被引用的文章:oracle.com/technetwork/issue-archive/2006/06-sep/…
    • order by 放在内部查询中很重要。我想知道,因为你原来的问题没有显示出来。
    猜你喜欢
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 2020-01-10
    • 2015-11-01
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多