我是ORM的粉丝 - 对象关系映射,过去一年半我一直在使用Rails。在此之前,我使用JDBC编写原始查询,并使数据库通过存储过程完成繁重的工作。使用ORM,我最初很高兴做coach.manager
和manager.coaches
之类的内容,这些内容非常简单易读。
但是随着时间的推移,有许多协会在爬行,我最终做了a.b.c.d
,它们在幕后向所有方向发射查询。使用rails和ruby,垃圾收集器变得疯狂,并且花费了大量时间来加载一个非常复杂的页面,其中包含相对较少的数据。我必须通过一个简单的存储过程替换这个ORM样式代码,我看到的结果是巨大的。现在需要花费50秒才能加载的页面只需2秒钟。
如果有这么大的差异,我应该继续使用ORM吗?很明显,与原始查询相比,它会产生严重的开销。
一般来说,使用像Hibernate,ActiveRecord这样的ORM框架会有什么常见的陷阱?
答案 0 :(得分:12)
ORM只是一种工具。如果你没有正确使用它,你会得到不好的结果。
没有什么能阻止您使用专用的HQL /条件查询(使用提取连接或投影)来返回页面必须尽可能少地显示的信息。这将与专用SQL查询或多或少同时进行。
但是,当然,如果您只是通过ID获取所有内容并浏览对象而未意识到它生成了多少查询,则会导致加载时间过长。关键是要确切了解ORM在场景背后的作用,并确定它是否合适或是否必须采用其他策略。
答案 1 :(得分:5)
我认为您已经确定了与ORM软件相关的主要权衡。每次添加一个新的抽象层,试图提供你曾经手工完成的事物的通用实现时,性能/效率会有所损失。
如您所述,遍历多个关系(例如a.b.c.d
)可能效率低下,因为大多数ORM软件将在此过程中为每个.
执行独立的数据库查询。但我不确定这意味着你应该完全消除ORM。大多数ORM解决方案(或者至少肯定是Hibernate)允许您指定自定义查询,您可以在单个数据库操作中准确地返回所需的内容。这应该与专用SQL一样快。
真正的问题是要了解ORM层在幕后的工作方式,并意识到虽然像a.b.c.d
这样的东西很容易编写,但它导致ORM层在评估时所做的事情并非如此。作为一般规则,我总是采用最简单的方法开始,然后在有意义的区域编写优化查询/很明显简单方法无法扩展。
答案 2 :(得分:3)
我会说,应该使用适当的工具来完成不同的任务。
例如,对于CRUD操作,像Hibernate这样的ORM框架可以加速开发,并且它将表现得足够好。有时你需要做一些必要的调整才能达到可接受的性能。我不确定,你的任务(用Hibernate花了50秒)用Hibernate无法正常完成,因为你没有向我们提供细节。
另一方面,例如涉及数十万条记录的批量操作并不是Hibernate在没有显着性能损失的情况下所要完成的任务类型。
答案 3 :(得分:2)
正如已经提到的那样,ORM只是一种工具,你可以使用它好坏。
ORM中最典型的性能问题之一是1 + N查询问题。它是通过从列表中为每个对象加载其他对象引起的。这是由于对列表中的每个元素的1-to-n-relation实体的急切获取引起的,处理是使用HQL查询,指定投影中的字段或标记将1-to-n关系取为lazy。
任何时候,您都必须确切知道ORM正在做什么才能获得良好的性能。不了解在后台进行的操作是一种导致灾难的方法(由于不必要和错误编写的解决方案,缓慢,错误和难以分析代码)。
答案 4 :(得分:1)
我和Petar在你关于懒惰取物的评论中。假设你有一个html表填充来自对象a.b.c.d的字段。您可以找到您的框架数千次对数据库进行四舍五入(可能更多)。在这种情况下,ORM的缺点是您必须彻底阅读文档。大多数框架都支持禁用延迟提取,许多框架甚至支持添加自己的处理逻辑来绑定数据集。
净输出几乎任何ORM几乎都比你自己写的任何东西都要好。您将发现自己背负着维护庞大的样板库或者更糟糕地反复编写相同的代码。
答案 5 :(得分:0)
我们目前正在研究从我们自己的数据存储层切换到传输对象和数据访问对象与JPA的清晰分离。我们使用生成器来创建TO,DAO和SQL DDL以及docbook格式的一些文档。通过这些我们所有的东西来自文档,数据库结构和生成的Java类,总是与数据库本身的良好文档同步。
到目前为止,我们使用JPA发现了什么: