【问题标题】:Maximum size for query collection parameter in JPA 2.1 / EclipseLink 2.5.2JPA 2.1 / EclipseLink 2.5.2 中查询集合参数的最大大小
【发布时间】:2014-10-09 08:56:36
【问题描述】:

JPA 2.1 / EclipseLink 2.5.2 中的查询集合参数是否有最大大小(连接到 mysql 5.6,如果有的话)?

例如,以下代码中ids 的最大允许和/或建议大小是多少,以确保性能并避免 JPA / EclipseLink / mysql 中的任何可能的错误或问题?:

@PersistenceContext
private EntityManager em;

{
    final Collection<Long> ids = /*obtain a Collection of IDs*/;

    em.createQuery("select e from Entity1 e where e.id in :ids")
        .setParameter("ids", ids);
}

【问题讨论】:

  • 我读过Oracle中的限制是1000个参数,但我没有看到Mysql的限制。您必须使用您的数据库进行测试,以了解更高的值如何影响性能。

标签: mysql jpa eclipselink jpa-2.0 jpa-2.1


【解决方案1】:

您的问题没有简单而明确的答案,因为它取决于多种因素,例如 JVM 的进程堆大小、持久性提供程序的专有功能、底层数据库调整选项等。在现实生活中,所有这些因素都应该调整而是单独的。


MySQL 5.6 参考手册12.3.2 比较函数和运算符一章定义:

IN 列表中的值数量仅受 max_allowed_packet 值。

由于 max_allowed_pa​​cket 等于一个数据包或任何生成/中间字符串(此处为:1GB)的最大大小,因此理论上应该允许您发送最大大小为 1GB 的查询字符串。


JPA 2.0 规范 (JSR-317),章节 4.6.9 In Experssions 没有提到任何关于限制的内容,所以至少我们可以假设这是一个问题工具链中“最弱”的组件(应用程序容器、持久性提供程序、底层数据库、JVM 堆大小)。


正如@Chris 所注意到的,Oracle 中每个语句的参数限制为 1000 个。 James(TopLink/EclipseLink 的前架构师)在他的blog 中描述了 EclipseLink 的类似问题:

我在这次运行中注意到的第一件事是 Oracle 有一个限制 每个语句 1,000 个参数。由于 IN 批量提取绑定了一个 大型数组,我正在读取 5,000 个对象,超出了此限制 并且运行因数据库错误而爆炸。 BatchFetchPolicy 中的 EclipseLink 考虑了这一点,定义了最大数量的大小 ids 包括一个 IN。 EclipseLink 中的默认大小限制是 假设是 500 (...)

EclipseLink 定义了一个 JPA 查询提示“eclipselink.batch.size” 允许设置大小因此我将其设置为 500 以进行测试。 这意味着要读入所有 5,000 个对象,IN 批处理 fetch 需要为每个批量获取的关系执行 10 次查询。

无论如何,我鼓励阅读整篇文章。

【讨论】:

  • 感谢您提供详细信息。似乎BatchFetchPolicy#size 仅用于使用BatchFetchType.IN 批量获取实体关系。 EclipseLink 2.5.2 可以配置为对用作查询值参数的集合进行分区吗?例如,如果我将 EclipseLink 配置为划分为 500 个元素块,并且如果我传入 10,000 个项目 Collection 作为查询参数值,当我在查询上调用 getResultList() 时,我希望 EclipseLink 运行查询 20 次每次运行 500 个元素,然后将结果连接成一个返回的 List
  • 您所描述的场景让人想起典型的“分页”。恐怕 JPA/EclipseLink 在内部不支持此类功能,而是通过提供带有 setMaxResultssetFirstResult 方法的 Query 接口将其委托给外部。从更通用的角度来看它 - 问题是特定于给定环境的,因此 EclipseLink 或 MySQL 不可能找出所有查询将以最高性能方式工作的完美边界。通常默认设置满足大多数环境,最终可能会被调整。
【解决方案2】:

“限制”是 SQL 中数据库中的任何限制。查看您的 JPA 提供程序创建的 SQL,然后查看您使用的 RDBMS 中该语法的限制

【讨论】:

    【解决方案3】:

    使用setMaxResults() 方法。

    例如结果如下

    1、2、3、4、5、6、7、8、9、10

    只有最大结果

    em.createQuery(...).setParameter(...).setMaxResults(5).getResultList();
    

    输出

    1、2、3、4、5

    范围的使用

    em.createQuery(...).setParameter(...).setFirstResult(3).setMaxResults(5).getResultList();
    

    输出

    4、5、6、7、8

    【讨论】:

    • 这不是我要找的。我不需要限制 JPA 查询的输出。我需要知道我可以安全地将多少项作为单个输入集合参数的成员传递给查询。
    【解决方案4】:

    openJPA 等其他框架能够为用户透明地拆分 SQL,因此,如果在带有占位符的 IN 子句中支持超过 1000 个项目的列表,则它会自动拆分。 如果 EclipseLink 也支持这样的特性会很好,因为它可以由实现自动化。将工作负载转移给用户,依赖于底层数据库,对开发人员不友好。

    【讨论】:

      猜你喜欢
      • 2014-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-09
      • 2018-02-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-19
      相关资源
      最近更新 更多