【问题标题】:JPA Native Queries versus 'pure' JPA persistenceJPA 原生查询与“纯”JPA 持久性
【发布时间】:2011-10-16 11:38:52
【问题描述】:

我有一个场景,我需要将所有传入文件(平面、xml)的日志记录到应用程序中。此日志表几乎不使用,除了故障调查或监管目的等,并且会定期清除数据。

我们使用 JPA 2.0 来实现持久性。我们立即使用entityManager.persist();flush 尝试了具有纯JPA 持久性的初始原型。但表现并没有达到预期。所以我建议NativeNamedQueries 进行此操作,测试时性能提升很大(300 毫秒对 47 毫秒)。

但首席工程师对使用 NativeNamedQueries 有点固执,说它与数据库耦合,可维护性较差等等。

问题:

  1. 如果您必须做出决定,您对此有何看法。应用程序投入生产后,数据库或架构更改多久发生一次?

  2. 还有其他方法可以提高性能吗?性能对于这个应用程序来说非常重要。

我开始编程仅 4 年,但从未见过现有应用程序发生数据库架构更改或数据库提供程序更改。

注意:我们使用的是 EclipseLink 2.3 和 Oracle。它也是我们正在开发的一个新应用程序。以防万一这些点使问题更清楚

【问题讨论】:

  • 请您的首席工程师说出两个在 INSERT 语句中具有不同语法的 RDBMS。在过去的 8 年中,我一直在编写 DataNucleus,它支持所有常见的 RDBMS,并且不需要不同的语法来处理所有内容(除了标识符的大写/小写,具体取决于架构如何定义它们)。
  • @DataNucleus OMG。我不敢相信来自 DataNucleus 的人会对我的问题发表评论。你知道,你必须与某人和他们的喜好一起生活。

标签: java database performance orm jpa


【解决方案1】:
  1. 您实际上确实 切换数据库提供商的情况非常罕见,尤其是在您为 Oracle 等优秀且高性能的数据库支付了数十万的许可证之后。此外,INSERT 语句的 SQL 语法变体并没有那么明显,以至于您无法切换数据库,即使在使用本机 SQL 时也是如此。

  2. 我不明白为什么修补需要额外调整的单个查询是不好的。问问你的首席开发人员为什么他这么严格。但在此之前,请使用分析器(例如 JProfiler 或 Yourkit)来确定导致性能问题的确切位置。使用 JPA,任何这些都可能导致问题:缓存、依赖数据的急切加载(您可能不需要)、低效的 SQL 生成、Oracle 数据库中的错误查询执行计划等......也许您不需要毕竟不需要原生查询。

  3. 如果性能如此关键,那么 JPA 可能不足以胜任这项工作。您(和您的首席开发人员)是否考虑过其他框架,例如 jOOQQueryDSLMyBatis 或类似的东西?我从您的 cmets 了解到,您的主要用例是 OLAP 查询,而不是 OLTP,因此您甚至可能喜欢使用高级 Oracle 功能,例如 jOOQ 原生支持的分析功能和数据仓库功能,用于实例...

【讨论】:

    【解决方案2】:

    应用程序投入生产后,数据库或架构更改多久发生一次?

    这对您手头的问题无关紧要。数据库模式的更改数量无关紧要。重要的是你的数据库模型的可维护性,它的设计有多好。如果没有进行足够的性能测试,大多数商业应用都会看到很多变化,这对于大多数应用来说是可悲的。

    如果您正在编写一个典型的业务线应用程序,我希望在开发过程中会在对象模型和数据库模型之间进行某种形式的往返工程。您的 DBA 应该拥有并非常了解数据库模型,以便他们可以帮助或执行微调 ORM 框架发出的查询。请记住,您可能不仅仅依赖于 ORM 框架发出的查询。所有更改最好在开发和集成测试(可能还有 UAT,如果你有的话)环境中完成和测试,然后再部署到生产环境中,并且正如常识所暗示的那样,所有更改都将受到版本控制。

    关于将查询耦合到数据库的主题,这是您的企业必须做出的决定。如果您从事支持多个数据库的业务,那么您应该针对所有数据库进行测试。此外,您应该能够提供不同的发行版来支持不同的数据库;如果您将本机查询放在特定于数据库的orm.xml 文件中,例如orm-oracle.xmlorm-mysql.xml 等,并在准备分发之前将文件重命名为orm.xml,这会变得更容易。使用 Maven 或 Ant 将使提议的更改易于实施。

    还有其他方法可以提高性能吗?性能对于这个应用程序来说非常关键。

    这取决于您设计对象和数据模型的程度、您对 ORM 框架的理解程度以及“破坏”对象模型的意愿。

    对任何应用程序进行性能调优的第一步是始终测量两次并削减一次。您不能简单地遍历可能的解决方案列表并尝试其中的每一个而不知道它们是如何工作的以及它们在什么情况下有用;好的,如果您的企业愿意为此投入时间,您可以这样做,但通常情况并非如此。

    首先,您需要了解原生查询为何提供或出现* 以提供更好的性能。也许这与您只是插入数据这一事实有很大关系,对于 ORM 框架来说,简单地发出 INSERT 语句而不是从 HQL 或底层使用的抽象查询符号构造一个语句会更好;只有分析器才能揭示差异。

    如果上述情况属实,那么您可以重新考虑您的审计表是否必须由 ORM 框架管理。如果您的应用程序只负责写入这些表而不是读取它们(并且很可能另一个应用程序负责读取条目),那么我怀疑不在 ORM 中管理这些表会提供更好的性能,尤其是如果您使用纯 JDBC 发出 INSERT 语句。原因很简单——如果您的 ORM 框架正在管理实体,那么它还负责管理持久化上下文(现在包括类和关联表);如果没有 ORM 管理实体,可能会导致根本不需要为审计条目更新持久性上下文的情况。

    您可以采取其他性能调整措施的健康可能性,但就像我之前所说的,这需要您了解分析器报告并估计哪些可能的选择在您的应用程序中会更好。

    * 恐怕除非您发布基准以及如何执行基准,否则我会对声明持怀疑态度。

    【讨论】:

    • 哇!!它的精彩答案。我将在星期一用基准更新这个问题。我们不需要 ORM 来管理持久性上下文,因为它不是事务性质的数据。它也是一个域和技术堆栈感知中间件。这就是为什么我选择 NativeQueries 在这里插入。此外,它是一个简单的 SQL 插入,应该适用于任何数据库。
    • @nobody,你不需要。我认为您在另一个问题中的评论为您提供了另一种调查的可能性。由于您使用的是BLOB,我认为您应该咨询您组织中的某个人,看看与签名/哈希关联的普通文件是否可以工作;毕竟这些都是审计条目。它可能会变得更好的原因是 Oracle 使用不同的段来存储 LOB,而不是与表关联的段。我怀疑如果你一开始不使用 LOB,内在的问题就会得到解决。
    • 我已经想到了。但是组织非常注重存储在数据库中,因为它是“安全的”,并且我们对在生产中写入文件系统有限制(施加的安全措施)。你知道我们在 MQ 中收到了 5MB 的文件(如果我的理解是正确的,MQ 不是为它设计的)。但我们必须提供最好的这些限制。所以 BLOB 是唯一的选择。
    • which if my understanding is correct, MQ is not designed for 同样适用于在数据库中存储该大小的文件。这就是我提出基于文件系统的解决方案的原因。此外,在数据库中存储某些内容并不会自动使审计条目无误;重要的是non-repudiabilitya validated chain of custody,如果您没有将审计表与正常业务表分开,并且没有使用单独的事务来插入审计条目,这并不容易。
    【解决方案3】:

    1) 我在 10 年内只看到了 2 个从 oracle 迁移到 MySQL 的应用程序(以节省许可成本),所以这不是经常发生的事情,但是如果你想使用另一个数据库编写集成测试(例如hsqldb) 你会有麻烦的。

    关于应用程序投入生产后架构更改的频率,我的回答是:很多!如果应用程序会定期更新,预计会有很多变化,因为通常团队更了解业务。我什至参与了一个应用程序上线一年后架构有很大不同的项目。

    与此同时,您似乎将优化推迟到最后可能的时间(这是一件好事),现在您需要使用一些本机查询来优化 sql(这也经常发生)...我想说的是,你的想法对我来说听起来一点也不坏。

    2) 过去我在类似的情况下混合使用了 Hibernate 和 iBatis(或现在的 mybatis)(以防你想检查 iBatis)。还有一个问题,你为什么要在每次persist() 之后执行flush()?你不应该真的需要这样做。

    另外,如果插入是在 EclipseLink 中完成的,我很惊讶插入需要更长的时间。对persist() 的调用应该花费与本机查询几乎相同的时间(我假设如果有任何生命周期回调它们会花费更长的时间)。假设你见过eclipseLink生成的sql,有那么不一样吗?

    我知道我的回答并不具体,但我希望它有所帮助。

    【讨论】:

    • 为什么我在收到文件后很快就刷新是,如果文件是重复的,那么就没有进一步的处理并且事务在那里结束。但是,如果文件不是重复的,则事务会继续进行,最后可能会使用刷新。没有生命周期回调。此外,查询看起来几乎相似。顺便说一句,它的简单插入查询有 6 列,其中之一是 BLOB。
    猜你喜欢
    • 2018-03-17
    • 2011-08-31
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多