【问题标题】:Strategies for performance optimizations on an inherited EJB3 application继承 EJB3 应用程序的性能优化策略
【发布时间】:2010-09-29 07:40:12
【问题描述】:

我被要求查看一个存在严重性能问题的遗留 EJB3 应用程序。原作者不再可用,所以我所拥有的只是源代码和一些关于不可接受的性能的用户 cmet。我个人的 EJB3 技能非常基础,我可以阅读和理解带注释的代码,但直到知道为止。

服务器有一个数据库、几个 EJB3 bean (JPA) 和一些无状态 bean,只是为了允许远程客户端对 4..5 域对象进行 CRUD。客户端本身是一个 java 应用程序。只有几个并行连接到服务器。我从用户 cmets 那里了解到

  • 客户端/服务器应用在 LAN 中表现良好
  • 该应用在 WAN(1MBit 或更多)上几乎无法使用,因为读取和更新操作花费的时间太长(长达几分钟)

我发现了一个潜在的问题 - 在所有 EJB 上,所有关系都使用获取策略 FetchType.EAGER 定义。这是否可以解释读取操作的性能问题,是否建议从获取策略开始调整?

但这并不能解释更新操作的性能问题,对吗?更新由EntityManager 处理,客户端只需将域对象传递给管理器 bean,并且只使用manager.persist(obj) 就可以完成持久化。可能发送到服务器的域对象太大(可能是 EAGER 策略的副作用)。

所以我的实际理论是通过相当慢的网络发送了太多字节,我应该考虑减少结果集的大小。

根据您的经验,导致 CRUD 操作性能问题的典型和最常见的编码错误是什么,我应该从哪里开始调查/优化?

【问题讨论】:

    标签: java performance jpa ejb-3.0


    【解决方案1】:

    在所有 EJB 上,所有关系都使用获取策略 FetchType.EAGER 定义。这能解释读取操作的性能问题吗?

    根据类之间的关系,您在检索实体时可能会获取比实际想要的更多(整个数据库?)?

    是否建议从获取策略开始调整?

    我不能说使所有关系都 EAGER 是一种非常标准的方法。根据我的经验,当您想为给定用例急切加载关联时,您通常会让它们保持惰性并使用 “Fetch Joins”(一种允许获取关联的连接)。

    但这并不能解释更新操作的性能问题,对吗?

    它可以。我的意思是,如果应用程序在读取时检索大胖对象图,然后将相同的胖对象图发送回仅更新根实体,则可能会降低性能。但是代码使用em.persist(Object)更新实体有点奇怪。

    根据您的经验,导致 CRUD 操作性能问题的典型和最常见的编码错误是什么,我应该从哪里开始调查/优化?

    明显的包括:

    1. 检索的数据多于所需数据
    2. N+1 请求问题(错误的抓取策略)
    3. JPQL 查询写得不好
    4. 不恰当的继承策略
    5. 不必要的数据库命中(即缺少缓存)

    我会先编写一些集成测试或功能测试,然后再进行任何操作,以保证您不会更改功能行为。然后,我将激活 SQL 日志记录并开始查看为主要用例生成的 SQL 并处理上述几点。

    【讨论】:

    • 仔细查看了 bean,作者使用persist 插入,merge 用于更新。这更有意义还是仍然很奇怪?
    • @Andreas_D 好的,这就是我所期待的。
    【解决方案2】:

    来自 DBA 职位。

    根据您的经验,导致 CRUD 操作性能问题的典型和最常见的编码错误是什么,我应该从哪里开始调查/优化?

    1. 关闭缓存
    2. 启用 sql 日志记录 Ejb3/Hibernate 默认会生成许多极其愚蠢的查询。
    3. 现在你明白我的意思了。
    4. 将 FetchType.EAGER 更改为 FetchType.LAZY
    5. 对 em.find em.persist 之间的大业务逻辑说“不”
    6. 使用ehcache http://ehcache.org/
    7. 开启实体缓存
    8. 如果可以,使主键不可变(@Column(updatable = false, ...)
    9. 开启查询缓存

    如果您想要高性能,就永远不要使用 Hibernate: http://www.google.com/search?q=hibernate+sucks

    【讨论】:

    • 谢谢!我将从(4)开始,因为我不认为服务器和数据库是实际的瓶颈。因此,FetchType.LAZY 可能已经显着提高了性能,并且.. 这将支持 Fake Jeffs(来自您的最后一个链接)的观点——Java 程序员一旦拥有了 hibernate/JPA 工具就不会考虑数据库——只是因为它非常简单坚持这几个对象;)
    • 最后一句完全错误,Hibernate 在熟练的人使用时表现非常好。
    • @Pascal - 当然,你是对的,我喜欢 hibernate - 但它打开了数据库的大门,比如说,不太熟练的人,我有一种感觉,其中一个离开了我的实际应用程序后面;)
    • @Andreas Hibernate 并不完美,它肯定有缺陷。但是“永远不要使用 Hibernate (...)”是一个非常保守的说法,这是不正确的。
    • Hibernate 有趣的男孩写道:“开发人员使用 Hibernate 是因为他们对 SQL 和 RDBMS 感到不自在。在开始使用 Hibernate 之前,您应该对 SQL 和 JDBC 非常熟悉 - Hibernate 建立在 JDBC 之上,它不是代替它。”对 sql,java,jdbc 非常熟悉的人可以为您提供数百个 ejb3 无法完成的 sql 和技巧。在可伸缩性和成本就是一切的地方,Java ORM 尤其是 Hibernate 没有立足之地。 alexa.com/topsites ejb3.
    【解决方案3】:

    在我的情况下,类似的性能问题并不取决于获取策略。或者可以说,改变现有获取策略中的业务逻辑是不可能的。在我的情况下,解决方案只是添加索引。 当您的 JPA 对象模型有很多关系(OneToOne、OneToMany、...)时,您通常会使用带有大量连接的 JPQL 语句。这可能导致复杂的 SQL 转换。当您查看数据模型(由 JPA 生成)时,您会发现您的任何表行都没有索引。 例如,如果您有一个 Customer 和一个具有 oneToOne 关系的 Address 对象,那么第一眼看起来一切都会很好。客户和地址有一个外键。但是如果你做这样的选择

    Select c from Customer as c where c.address.zip='8888'

    您应该注意表格 ADDRESS 中的表格列“zip”。 JPA 在部署期间不会为您创建这样的索引。因此,就我而言,我可以通过简单地添加索引来加快数据库性能。 数据库中的 SQL 语句如下所示:

     ALTER TABLE `mydatabase`.`ADDRESS` ADD INDEX `zip_index`(`IZIP`);
    

    【讨论】:

    • 谢谢!幸运的是,我很长一段时间都不需要查看那个...代码库,但是有一个风险,即围绕这个项目的新任务即将到来,这肯定是首先要调查的事情之一。跨度>
    【解决方案4】:

    在这个问题和其他答案中,我听到了很多“可能”和“也许”。

    首先找出发生了什么。如果你还没有这样做,我们都只是在黑暗中摸索。

    我不是这种系统的专家,但this method 可以在任何语言或操作系统上工作。

    当你发现是什么让它花费了太长时间时,你为什么不在这里总结一下呢? 我特别想知道这是否是被猜到的。

    【讨论】:

      猜你喜欢
      • 2011-05-19
      • 2012-06-10
      • 1970-01-01
      • 1970-01-01
      • 2010-10-29
      • 2019-06-19
      • 1970-01-01
      • 2018-07-02
      相关资源
      最近更新 更多