需要执行批量操作时,是否应该放弃ORM框架?


15

这是一种常见情况:

  • 您需要在使用ORM框架的应用程序中实现批量操作。
  • 第一次通过之后,您已经注意到严重的性能问题。

这是我的问题:

  • 在这种情况下,您是否应该支持包含原始SQL的解决方案?
  • 还是有众所周知的设计模式可以帮助您缓解与ORM框架的批量操作通常相关的问题?

编辑:

  • 我不是问您是否应该从整个应用程序中删除ORM框架。
  • 我在问:您是否应该为该应用程序的这一小部分放弃ORM框架?

我不知道您是否应该做任何事情,但是您是否尝试过分批批量操作?
ChrisAnnODell 2011年

Answers:


13

ORM并不是要完全接管对数据库的访问。将它们用于80%的CRUD代码中,这些代码太繁琐而无法自己编写。对于需要仔细优化的其余20%,请使用存储过程,动态SQL或任何您想要的东西。


4
如果数据库抽象不是您决定使用ORM的主要原因之一,那将起作用。

@ Pierre303,我很难理解您的评论。你什么意思?
Mark Canlas

@MarkCanlas:我认为他的意思是“抽象数据库”,如果您愿意的话,您可以更改数据库(例如,从SQL Server到MySQL)。实际上,这种用例几乎不会发生。
罗伯特·哈维,

1
您仍然可以创建抽象。实际上支持多个提供者/方言的大多数ORM都支持特定于提供者/方言的代码。您可以将操作实现为批量插入/数组绑定/ TVP /针对特定数据库的任何操作,对于不受支持的提供程序(如SQLite),可以让操作慢下来。在最坏的情况下,您可以基于build或config参数将可能的批量功能分解为单独的接口/类和子类,并位于不同的实现中。
2011年

是的,自定义方言以及针对特定问题的特定代码都可以提供帮助。但是,要使其在财务上可行,必须将其限制在严格的最低限度内。我们的定制化定制功能(方言)占数据访问代码库总数的不到0.1%。我真的会担心是否还不止于此。

7

我在需要高性能并处理数十亿条记录的应用程序中使用ORM(nHibernate)。随着时间的流逝,我们注意到最重要的性能问题与我们自己使用ORM的方式有关,而不是仅由于ORM。

ORM不应替代您的强制性数据库知识。它是用来在代码中提高生产力和灵活性的一种工具,但是您需要了解底层流程才能优化性能。

您没有指定特定的ORM,因此以下是我们为提高性能所做的工作:

  • 我们使用了ORM分析器。(我们使用了nhprof)
  • 我们使用了数据库探查器。(我们使用了SQL Server Profiler)
  • 我们阅读了有关该主题的文章。(除了文档中有关该主题的整章内容外,nHibernate还提供了许多功能)
  • 我们购买了有关性能和可伸缩性的特定书籍。
  • 我们创建了基准测试系统来测试我们自己的优化。
  • 更重要的是,我们能够与拥有大量数据的真实客户一起测试我们的代码。仅这最后一件事就帮助我们发现了应用程序中的大多数问题。

1

我们设法使用Entity Framework做到了这一点,但是我们的应用程序执行了很多批处理式操作(我们将大量记录写入单个表),因此非常适合。我肯定会看是否有可能保留ORM框架,只是为了减少应用程序中的特殊用途代码。是否可以缓冲写入,然后成组执行?您失去了事务语义,但是如果您要进行批量操作,我想您已经习惯了。


1

ORM没有神奇的作用。它们将对象访问方法转换为SQL。它们执行的SQL语句不一定比您手动编写的SQL慢。话虽如此,您可能会遇到一些问题:

  1. 事务:一次大批量操作几乎总是比共同完成同一件事的许多小事务要快。因此,如果您的ORM方法调用使用细粒度的事务(例如,默认情况下,Spring Roo实体中的活动记录样式方法被注释为@Transactional),则批量操作将很慢。如果您的应用程序是这种情况,则应查看事务逻辑。
  2. 缓存:在Hibernate中,一级缓存使您的实体管理器可以避免不必要的数据库往返。一般而言,这是件好事,但对于大容量插入却不利,因为这会导致不必要的缓存阻塞,从而导致应用程序性能下降。如果这是您的问题,则应查看ChrisAnnODell上面建议的“批处理”模式。我们在进口商中使用它,它大大加快了批量插入的速度。

使用本机SQL来提高性能没有错。但是首先要确保您了解导致您减速的原因。


为了避免缓存,请使用StatelessSession。另外,请避免使用自动递增ID。应该改用HiLo或Guid。

1

绕过ORM。不仅如此,还绕过“常规” sql。使用数据库的批量实用程序将非常大的数据集插入到临时表中。然后使用sql执行您的登台活动。

您的“博客风格” ORM可能不适用于所有情况。


是的,这类后端工具很容易学习,但是经过大约3或4次学习之后,您将成为专家,可以更快地完成工作,有时可以做其他事情无法完成的事情。就像铲子和推土机之间的区别一样。我已经为各种平台编写了脚本控制的工具,以读取文本输入文件并使用低级操作更新数据。编写这样的工具还可以使您的生活更轻松(或至少更有趣)。这样的事情可用于在软件更新期间调整客户端安装上的自定义数据。

0

处于那种情况。有时,您必须这样做。

一些ORM允许开发人员跳过对象模型,而直接进入数据库层。

还有一些ORM,它们使用批量操作封装为面向对象。


0

umlcat所述,有些ORM可以让您使用批量操作。

更好的是,许多ORM是可扩展的,因此,如果尚未支持,则可以编写自己的方法来运行批量操作。如果您可以排除应用程序中的批量操作,我将其添加为ORM上的一层(为此,您可能需要编写原始SQL),然后在应用程序中使用ORM您已实现的方法。

这也使单元测试和调试更加容易。一旦您对ORM方法的测试覆盖面广,就可以在应用程序中自由使用它。否则,调试原始SQL(尤其是带有事务和许多JOIN的大型SQL)可能会很麻烦。

有一次,我花了将近一天的时间在原始SQL调用中发现了一个错误,该错误将近100个LOC,而该错误只是一个字符!从那时起,我尝试避免在应用程序中使用原始SQL,并对所有SQL过程进行单独的单元测试。


0

好吧,我没有意识到任何设计模式。我的猜测是您为ORM做出决定是有原因的,因此放弃ORM可能不是您想要的。但是,在这些情况下,我认为混合两种解决方案都有空间。只要您有意识地做到这一点并记录为什么您偏离软件中默认使用ORM的原因,这没有什么错。紧接着,一些ORM框架具有执行批量操作的功能。我知道nHibernate(用于.NET框架的ORM)具有所谓的StatelessSessions,它们的开销要少得多,但这可能仍不能为您提供所需的性能提升。在这种情况下,只需使用原始SQL。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.