【问题标题】:Spring JPA Repository n+1 problems, EBEAN alternativeSpring JPA Repository n+1 问题,EBEAN 替代方案
【发布时间】:2015-02-22 10:05:57
【问题描述】:

我正在为现有的 MySQL 数据库编写基于 Java 的服务器。我可以更改数据库的结构,但任何更改也意味着挖掘一个相当古老的 CakePHP 项目,我希望尽可能不改动那个项目。

我对 Java 中的数据库访问没有太多经验,所以当我开始寻找一个好的框架时,我最终选择了 Spring Data Repositories(主要是因为我已经拥有用于 REST 服务的 Spring Boot Actuator)并且因为滚动 Hibernate 或手动执行其他 JPA 实现似乎既繁琐又复杂。

现在的问题是,我的查询速度不是很快。一个例子是查询我的约 200 个用户,并加载他们的关联(user.groups、user.groups.rights、user.groups.rights.permissions、user.rights、user.rights.permissions、users.nfc_keys)。我需要所有这些数据,因为连接到 Java 服务器的客户端之一需要这些信息来登录用户,即使主服务器出现故障并加快登录速度(换句话说,它会缓存信息)。

问题是,查询需要 8 秒才能执行!我知道这些问题,具体来说是 n+1 问题。因为我所有的收藏都是延迟加载的,所以休眠会为每个用户单独查询组、groups.rights、....。例如,我的组字段如下所示:

@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
@JoinTable(
        name = "user_group_memberships",
        joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
        inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
)
private List<Group> groups;

我尝试将 FetchType 更改为 EAGER,唯一要做的就是通过查询急切地获取所有组,但不是使用 SQL 连接,而是再次通过执行 n 查询。

我查看了this blog post 并在 UserRepository 中实现了一个查询,使用 LEFT JOIN FETCH 加载信息,需要从 Lists 更改为 Sets,由于我的 hashCode/equals 实现而对空指针问题感到恼火,再次延迟加载/设置代理,发现查询时间减少到大约 2 秒,这还不错,但与 CakePHP 执行相同查询所需的时间相比仍然非常慢。

我现在的问题主要是:是否有直接的解决方案可以使用 Spring Data Repositories 解决这些问题,或者我是否最好切换到不同的框架(在这个早期的项目阶段仍有可能)?我专门查看了 Play 框架中使用的 Ebeans,它们似乎有一个非常好的 API,并且还允许定义获取路径(这应该更好地解决 n+1 问题),但是我也读到了该项目维护不善的信息。你有什么意见?

【问题讨论】:

  • 您需要启用查询日志,并研究MySql创建的查询计划。如果查询没有使用您期望的索引(您会看到表扫描等),您可能必须添加索引或手动制作查询。

标签: java spring hibernate ebean


【解决方案1】:

请注意,由于我是 Ebean ORM 的主要维护者,所以我有偏见。

Ebean 存在的主要原因之一是因为我认为 JPQL 在优化 ORM 查询/对象图构造方面设计不佳。特别是缺乏对“partial objects”和“fetch paths”的支持。在某种程度上,JPA 获取组试图解决这些问题,但是您注意到这两个问题都由 Ebeans 查询语言直接处理。 JPA 提取组不符合 IMO(例如来自 DB、L2 和 L3 的混合对象图构造)。

请注意,我在生活中的忙碌时期(孩子等)故意让 Ebean 保持低调。 Ebean ORM 有一个赞助商,如果您查看项目发布,您会发现它运行良好。

Ebean ORM 实际上已经 10 岁了,所以它并不是一个新的或年轻的项目。

就在最近 ElasticSearch 集成 已发布,能够从 ElasticSearch 构建对象图(或对象图的路径)。这可以在不加载数据库的情况下增加读取可扩展性。

此外,您可能知道 Ebean 可以分析应用程序并自动调整 ORM 查询(如果您还没有,请查看视频)。

希望这会有所帮助。 干杯,罗伯。

更新: 添加一些链接供对细节感兴趣的人参考(并避免 N + 1、优化 ORM 查询等):

【讨论】:

    【解决方案2】:

    查询速度与很多事情有关:

    1.Driver - 2.Database - 3.Connection pooling 配置

    作为我在 JPA 的经验:

    尝试在视图层打开会话并尝试使用 HikariCP 将 加快连接速度

    【讨论】:

    • 我们将为我的测试做一个微基准测试。 JUnit测试只运行这个查询,这些问题真的可以通过使用不同的连接池来解决吗??
    • 一些使用块的连接池,使用不同的概念,帮助连接永不疲倦。另外你现在使用 Java 用于企业,它需要比 php 更多的字节码,会话将保留我的内存,php 存储会话在磁盘中的每个req resp中,帮助php减少内存使用,如果您熟悉sql,请使用jdbctemplate使用更少的内存和更快的速度
    猜你喜欢
    • 2021-11-06
    • 2023-03-12
    • 2021-08-26
    • 2015-12-03
    • 2020-08-21
    • 1970-01-01
    • 2017-12-31
    • 2011-01-27
    • 1970-01-01
    相关资源
    最近更新 更多