ORM使用的优化

时间:2010-03-06 11:13:12

标签: performance optimization orm jpa java-ee

我正在教Java EE,尤其是JPA,Spring和Spring MVC。由于我在大型项目方面没有太多经验,因此很难知道如何向学生介绍ORM的优化。

目前,我提出了一些经典的优化技巧:

  • 准备好的陈述(默认情况下大多数ORM隐含使用它们)
  • 第一级和第二级缓存
  • “先写,稍后优化”
  • 可以关闭ORM并将SQL命令直接发送到数据库,以获得非常频繁,专业和昂贵的请求

社区是否还有其他方面可以了解优化ORM的其他方法?我对DAO模式特别感兴趣......

6 个答案:

答案 0 :(得分:5)

从开发人员的角度来看,他必须处理以下优化案例:

    ORM和DB之间的
  • 减少chattiness 。低聊天很重要,因为ORM和数据库之间的每次往返都意味着网络交互,因此其长度至少在0.1到1ms之间变化 - 独立于查询complxity (请注意,可能90%的查询通常是相当简单)。特殊情况是 SELECT N + 1问题:如果处理某些查询结果的每一行需要执行一个额外的查询(因此总计执行1 + count(...)个查询),开发人员必须尝试以这样的方式重写代码,即执行几乎恒定的查询计数。 CRUD序列批处理将来的查询是优化减少chattines的其他示例(如下所述)。
  • 降低查询复杂性。通常ORM在这里很无奈,所以这只是开发人员的头疼。但是,允许直接执行SQL命令的API通常也适用于这种情况。

所以我可以进行更多优化:

  • 未来查询:一种API,允许延迟执行查询,直到需要其结果为止。如果此时安排了多个未来查询,则它们将作为单个批处理全部执行。因此,这样做的主要好处是减少了往返数据库的数量(=减少ORM和DB之间的干扰)。许多ORM实现了这一点,例如NHibernate的。
  • CRUD序列批处理:几乎相同,但是当INSERT,UPDATE和DELETE语句一起批处理以减少chattines。同样,由许多ORM工具实现。
  • 上述两种情况的结合 - 所谓的“广义批处理”。到目前为止,AFAIK只能由DataObjects.Net(我的团队工作的ORM)实现。
  • 异步通用批处理:如果批处理不需要立即回复,则它是异步执行的(当然,与同一会话发送的其他批处理同步,即基础连接无论如何同步使用)。当存在大量CRUD语句时带来显着的好处:修改持久实体的代码与DB端操作并行执行。到目前为止,没有ORM实现此优化。

所有这些案例都符合“先写,后优化”规则(或“先表达意向,后来优化”)。

另一个众所周知的与优化相关的API是预取API (“预取路径”)。背后的想法是获取预期以最少的查询次数进行处理的对象图(或者更好,在最短的时间内)。所以这个API解决了“SELECT N + 1”问题。同样,这部分通常预计会在任何严肃的ORM产品中实施。

以上所有优化都是从事务隔离的角度来看是安全的 - 即它们不会破坏它。从这一点来看,与缓存相关的优化通常是不安全的:您必须仔细配置缓存,以确保在获取实际内容很重要时(例如,在安全检查或某些实时交互时),您将不会获得过时的对象。这里有很多技术,从使用内置缓存开始,与分布式缓存集成( memcached 等)。任何解决问题的方法都很好;我个人希望一个开放的API允许将任何一个与我喜欢的缓存集成。

P.S。我是一名.NET粉丝,以及DataObjects.NetORMeter.NET开发人员之一。所以我不知道在Java中如何实现完全相似的功能,但我熟悉可用解决方案的范围。

答案 1 :(得分:1)

N + 1查询集合怎么样?例如,请参见此处:ORM Select n + 1 performance; join or no join

答案 2 :(得分:1)

关于Spring和Spring MVC,您可能会发现this很有趣。 它是用C ++编写的,而不是Java,但它展示了如何减少UI源代码w.r.t.春天一个数量级。

答案 3 :(得分:1)

懒惰 - loading通过代理可能是ORM的杀手级功能之一。

此外,Hibernate还能够代理object.collection.count之类的请求并对其进行优化,因此不会检索整个集合,只会导致SELECT Count(*)问题。

答案 4 :(得分:1)

你提到了DAO模式,但JPA阵营中的很多人都说这种模式已经死了(我认为Hibernate的人已经在博客上写过这个,但我记不清了这个链接)。看一下Spring Roo,了解他们如何通过静态方法将ORM相关功能直接添加到域模型中。

答案 5 :(得分:1)