使用的是ORM还是纯SQL?[关闭]


245

对于我开发的某些应用程序(后来逐渐忘记了),我一直在编写纯SQL,主要是针对MySQL。尽管我在SQLAlchemy之类的python中使用过ORM ,但是我并没有坚持很长时间。通常这是文档或复杂性(从我的角度来看)使我退缩。

我这样看:如果要使用一种数据库,则使用ORM进行可移植性,使用普通SQL。我真的在寻求有关在开发需要数据库支持的应用程序时何时使用ORM或SQL的建议。

考虑一下,与使用ORM相比,仅使用轻量级包装器来处理数据库不一致会更好。


标准化,安全性,可维护性,语言抽象,DRY等
2014年

与ORM性能可以接近SQL,取决于如果你正确地使用它,并用正确的设置...查看豪使EF6.x速度提高5:linkedin.com/pulse/...
巴希

对于ORM架构和如何做(避免的),这里是我的另一个链接:linkedin.com/pulse/...
巴希

对象关系映射(ORM)在许多编程语言中已经非常流行,并且是SQL的最佳替代之一。我从方法链风格中得到启发,为我的TRIADB项目创建了CQL。healis.eu/triadb/#latest-release
Athanassios

2
这个问题被关闭真是愚蠢。
米奇·

Answers:


169

ORM具有一些不错的功能。他们可以处理将数据库列复制到对象字段的繁琐工作。他们通常负责将语言的日期和时间类型转换为适当的数据库类型。它们通常还可以通过实例化嵌套对象来优雅地处理一对多关系。我发现如果您在设计数据库时考虑了ORM的优点和缺点,那么在将数据移入或移出数据库时可以节省很多工作。(如果需要映射它们,您将想知道它如何处理多态性和多对多关系。正是这两个域提供了大多数“阻抗不匹配”,这使得有些人将ORM称为“计算机科学的越南”。 )

对于事务性应用程序,即您发出请求,获取一些对象,遍历它们以获取一些数据并将其呈现在网页上,性能负担很小,在许多情况下,ORM可以更快,因为它将缓存对象,如前所述,否则将多次查询数据库。

对于报表繁重的应用程序,或每个请求要处理大量数据库行的应用程序,ORM负担要重得多,并且它们所做的缓存会变成很大的无用的内存消耗负担。在这种情况下,精简DAL中的简单SQL映射(LinQ或iBatis)或手工编码的SQL查询就是解决之道。

对于任何大型应用程序,我都发现您会同时使用这两种方法。(ORM用于简单的CRUD,而SQL / thin DAL用于报告)。


您可以定义“每个请求大量的数据库行”吗?请:)
Mosselman

那么我可以将JPA与IBatis集成在一起吗?是否让它们在同一笔交易中工作?
Jaime Hablutzel 2011年

2
似乎没有人讨论的另一个考虑因素是基本的国家管理。整个框架堆栈(JSF,JPA等)都基于Java bean的get / set方法。这是每张桌子,每列的一叠样板,而...这是真正的反模式:只是公开每个字段,就好像它是公共的一样。实际上,在对象/表/行中的字段上使用get / set方法非常接近违反每个租户的信息隐藏和封装方法。最后,回到状态管理...不变性选项在哪里?是否可以或应该允许半设置对象?大多数没有选择。
Darrell Teague

2
我想磨练并特别同意此答案中的关键声明。“对于每个请求处理大量数据库行的应用程序,ORM税要重得多”。ORM仅对开发人员和维护人员有好处,因为大多数开发人员都不擅长SQL,但是如果您实际上是在谈论性能,那么SQL绝对会胜过它。
Manachi

“大多数开发人员都不擅长SQL” ????我要说的是,大多数开发人员都不知道如何正确使用LINQ,表达式树的功能以及常规的ORM,代码生成以及许多其他功能。但是,不,我没有任何依据可以做出如此有力的声明。
AdanayMartín17年

253

以花很多时间使用JPA(Java持久性API,基本上是Java / J2EE / EJB的标准化ORM API)的人(包括Hibernate,EclipseLink,Toplink,OpenJPA等)发言,我将分享一些我的知识。观察。

  1. ORM并不快。它们可以满足需要,并且在大多数情况下可以满足要求,但是在高容量,低延迟的环境中,它们是不行的。
  2. 在像Java和C#这样的通用编程语言中,您需要大量的魔术才能使它们工作(例如,使用Java进行加载时编织,检测等);
  3. 当使用ORM时,而不是进一步了解SQL(这似乎是要这样做的),您会惊讶地花了多少时间来调整XML和/或注释/属性,以使ORM生成高性能的SQL。
  4. 对于复杂的查询,确实没有替代品。就像在JPA中一样,原始SQL中根本不可能进行一些查询,并且当您不得不在JPA中使用原始SQL时,它就不太好了(C#/。Net至少具有动态类型var),这很多比Object数组更好);
  5. 使用ORM时有很多“陷阱”。这包括意外或意外的行为,事实是您必须建立对数据库进行SQL更新的功能(通过在JPA中使用refresh()或类似方法),因为JPA默认情况下会缓存所有内容,因此它不会捕获直接数据库更新-运行直接SQL更新是常见的生产支持活动);
  6. 对象关系不匹配总是会引起问题。对于任何此类问题,都需要在抽象的复杂性和完整性之间进行权衡。有时我觉得JPA太过分了,碰到了收益递减的真实法则,而复杂性的打击并没有通过抽象来证明。

还有另一个问题需要更多解释。

Web应用程序的传统模型是具有一个持久层和一个表示层(可能在它们之间有一个服务或其他层,但这是本次讨论的重要两层)。ORM强制从您的持久性层到表示层(即您的实体)的僵化视图。

对更多原始SQL方法的批评之一是,您最终只能使用一个查询使用所有这些VO(值对象)或DTO(数据传输对象)。吹捧这是ORM的优势,因为您摆脱了这一点。

问题是,ORM并不会解决这些问题,它们只会上升到表示层。您无需创建查询的VO / DTO,而是创建自定义的表示对象,通常为每个视图一个。这样更好吗 恕我直言,事实并非如此。

我已经在ORM或SQL中写过这本书:我们到了吗?

最近,我选择的(在Java中)持久性技术是ibatis。它是围绕SQL的一个非常薄的包装程序,可以完成JPA可以完成的90%以上的工作(尽管它没有详细记录,它甚至可以进行关系的延迟加载),但开销却少得多(就复杂性和实际代码而言)。

这是去年在我正在编写的GWT应用程序中出现的。从EclipseLink到服务实现中的表示对象的大量转换。如果我们使用ibatis,那么使用ibatis创建合适的对象然后将它们一直沿堆栈上下传递要简单得多。一些纯粹主义者可能会认为这是Bad™。也许是这样(理论上),但是我告诉你什么:它可以导致更简单的代码,更简单的堆栈和更高的生产率。


2
我受到启发而提出了另一个(尽管是社区维基百科)问题,只是为了收集有关此类事情的资源。关于最后一段:我喜欢简单。可能太多了。
hydrapheetz

3
iBATIS很棒,但也许您会想尝试jOOQ:jooq.sourceforge.net。由于您提到的6个原因,它的主要重点恰恰是与SQL保持紧密联系。
卢卡斯·埃德

5
对于点3 +1。许多人认为使用ORM会使您对SQL失去透彻的了解。事实是,一旦您可以/学会使用SQL进行体操,就可能很快就会离开ORM。
瑞安·费尔南德斯

4
因此,现在是2013年底,众所周知,没有什么比“老实话”更具误导性的了-我可以问一下您的观点是否仍然相同吗?如果没有,那么最好写一篇博客文章/相应地更新答案。
多米尼克

3
var在.NET中不会产生动态类型,带有dynamic关键字的变量是.NET中的动态类型。var仍然是静态类型。见stackoverflow.com/questions/961581/...
筏子

45

我说普通的SQL代表R eads,ORM代表CUD

性能是我一直关注的问题,尤其是在Web应用程序中,同时也是代码的可维护性和可读性。为了解决这些问题,我写了SqlBuilder


1
什么是CUD?我找不到定义。
Kimchi Man

27
@不带R的KimchiMan CRUD
马克斯·托罗

3
CUD-创建,更新,删除。
合并

14

ORM不仅是可移植性(就此而言,即使使用ORM也很难实现)。当ORM工具使您免于编写样板化的SQL查询(通过PK或谓词,插入,更新和删除进行选择)并使您专注于问题域时,它为您提供的基本上是持久性存储上的抽象层。


3
我正在考虑更接近跨数据库风格的可移植性。我不应该在深夜发布问题。
hydrapheetz,2009年

1
我的意思就是这样:即使是最基本的方案,也可能会在不同的DBMS中发生错误-例如,对NULL的不同处理。
安东·戈戈列夫(

ORM为您提供了对象之间关系的抽象层,但是对于您提到的样板查询并没有很大的优势。在JDBC应用程序中,您可以在抽象超类或实用程序类中用少量代码编写这些类型的查询。无需为每个新表重复样板。
凯文·斯特布里奇

11

任何合理的设计都需要对数据库进行某种抽象,以处理阻抗不匹配的问题。但是我希望最简单的第一步(对于大多数情况而言是足够的)将是DAL,而不是重量级的ORM。您唯一的选择不是在频谱的末端。


编辑以回应要求我描述我如何区分DAL和ORM的评论:

DAL是您自己编写的,也许是从只封装表并将其字段映射到属性的类开始的。ORM是您不编写的代码,也不是从dbms模式的其他属性(主要是PK和FK)推断出的抽象机制。(在这里您可以找到自动抽象是否开始泄漏。我宁愿有意地通知他们,但这可能只是我个人的喜好)。


2
您在什么是DAL和什么是ORM之间划清界限?
混乱

4
因此,如果您是ORM的作者,那么您的ORM会自动转回DAL吗?:)
孟买,2012年

DAL =持久层,而ORM是在DAL内部使用的工具,用于对数据存储执行CRUD操作。
Vahid Ghadiri

7

每个工具都有其目的和愿景。我创建了http://www.jooq.org/正是为了满足您的需求,尽管iBatis可能也是您的理想选择。

jOOQ具有基本的ORM功能,但主要集中于我想大多数开发人员在尝试找到最适合他们需求的ORM时最需要的功能:

  • 代码生成
  • 变量绑定(这在JDBC中很痛苦)
  • SQL语法抽象(以防止语法错误)

但是通常它们走得太远,提供了太多的抽象,您不会认为它们正在针对RDBMS运行。另一方面,您选择RDBMS正是因为

  • 它是一个强大的数据源
  • SQL可以完成许多好的性能工作(嵌套选择,联合,复杂联接等)。通常,ORM无法执行这些操作。
  • 您可以自己处理交易和会话
  • 您有UDT和存储过程

jOOQ正好解决了这些问题。它的性能将与JDBC一样好,但没有痛苦。


6

在现代软件开发方案中,是否使用框架的难题非常普遍。

需要理解的重要一点是,每种框架或方法都有其优缺点-例如,根据我们的经验,我们发现ORM在处理事务(即插入/更新/删除操作)时很有用-但是在处理复杂的数据时结果,评估ORM工具的性能和有效性变得很重要。

同样重要的是要了解选择一个框架或方法并实施其中的所有内容不是强制性的。我们的意思是说,我们可以混合使用ORM和本机查询语言。许多ORM框架在本机SQL中为插件提供了扩展点。我们应该尽量不要过度使用框架或方法。我们可以结合某些框架或方法,并提供适当的解决方案。

在涉及高并发性的插入,更新,删除,版本控制时,您可以使用ORM,并且可以使用Native SQL来生成报告和详细列出清单。


3
为什么ORM更适合高并发性?
user359996 2011年

6

使我的ORM真正发挥作用的关键是代码生成。我同意,就代码性能而言,ORM路由并不是最快的。但是,当您拥有中型到大型团队时,数据库正在迅速变化,在构建过程中,从数据库重新生成类和映射的能力令人眼前一亮,尤其是当您使用CI时。因此,您的代码可能不是最快的,但是您的代码将是-我知道我将在大多数项目中采用哪种代码。

我的建议是在Schema仍然运行时使用ORM进行开发,使用性能分析来查找瓶颈,然后使用原始Sql调整那些需要它的区域。

另一个想法是,如果使用正确的方式,内置在Hibernate中的缓存通常可以大大提高性能。无需再回到数据库读取参考数据了。


2
绝对是个人品味的问题。对我来说,代码生成是一个缺陷。
dkretz

5
阅读第二段....也许完整性也很有用
MrTelly

代码生成是更快地完成某些任务的唯一方法。像所有工具一样,它可能功能强大或导致灾难。从技术上讲,所有语言都在生成其他类型的代码。
Banjocat 2015年

4

没有“一刀切”的解决方案,对于“我是否应该使用or / m?'。

我会说:如果您必须编写一个非常注重“数据”的应用程序/工具,而没有太多其他逻辑,那么我将使用普通SQL,因为SQL是此类应用程序的领域特定语言。

另一方面,如果我要编写一个包含很多“域”逻辑的业务/企业应用程序,那么我将编写一个丰富的类模型,该模型可以用代码表达该域。在这种情况下,OR / M映射器可能对成功完成操作非常有帮助,因为它需要大量的管道代码。


“没有“一刀切”的解决方案” ..应该有。
鲁西诺2011年

1

我开发的应用程序之一是用python编写的IRC机器人。它使用的模块在单独的线程中运行,但我还没有找到使用sqlite时处理线程的方法。不过,对于一个单独的问题可能会更好。

我真的应该只改写标题实际问题。我以前从未真正使用过任何语言的DAL。


4
好吧,我认为你应该。原始SQL到处都是可恶的。
混乱

是的,是的。我不时黑客攻击一个论坛软件,到处都是大量的mysql_query()和mysql_result()。疯了
hydrapheetz,2009年

您所说的“应用”是什么?
Zoran Pavlovic

有趣的是,这个问题是通过irc机器人应用程序提出的,并成为了一个问题(非常有用的指南)!一个irc bot应用程序处于规模的另一端,而具有50-100个以上具有复杂联接的表和数百万行数据且由20多个开发人员进行工作的应用程序处于规模的另一端。我敢说,当涉及到“ irc bot app”规模时,这无关紧要。
Manachi

1

使用 SQL 相似但提供编译时检查和类型安全性的ORM 。就像我最喜欢的:数据知识对象(公开:我写的)

例如:

for (Bug bug : Bug.ALL.limit(100)) {
  int id = bug.getId();
  String title = bug.getTitle();
  System.out.println(id +" "+ title);
}

完全流式传输。易于设置(无需定义映射-读取现有架构)。支持联接,事务,内部查询,聚合等。您几乎可以在SQL中执行任何操作。并且已经从巨型数据集(财务时间序列)一直到微不足道(Android)进行了证明。


您的IDE也可以直接提供此类静态检查(IDEA知道数据库结构,只要您告诉它数据库在哪里/ DDL文件在哪里,那么它就可以在SQL查询/过程/任何类型中进行类型检查/关系检查/等等。 )
Xenos

这很有用。它可以作为build / CI步骤的一部分吗?如何对sql和其他字符串进行分类?它可以处理字符串操作还是仅处理字符串常量?
keredson '19

我会被abBlock所阻止,但是IntelliJ像其他任何语言一样都会解析SQL jetbrains.com/datagrip/features,这样就可以将其集成到CI / CD / build中(也许通过要求IJ团队隔离SQL解析代码?也许已经有Sonar了)有这样的解析器)。解析带来了数据类型,因此您可以对其进行检查(我已经使用自定义插件完成了检查),或者进行了诸如“ JOIN列是否具有FK?索引?”之类的检查。等等,这些将是整齐的改进措施,本地IJ的SQL检查
的Xenos

1

我知道这个问题很老,但是我认为我会发布答案,以防有人遇到像我这样的人。ORM已经走了很长一段路。实际上,其中一些功能可以为您提供两全其美的优势:提高开发效率和保持性能。

看一下SQL数据(http://sqldata.codeplex.com)。这是一个非常轻巧的c#ORM,涵盖了所有基础。

仅供参考,我是SQL Data的作者。


1

我想在回答“有一个中间立场!”的答复中加入我的声音。

对于应用程序程序员而言,SQL是您可能要控制的事物和几乎肯定不希望控制的事物的混合体。

我一直想要的是一个层(称为DAL,ORM或微型ORM,我不介意哪一个),它将负责完全可预测的决策(如何拼写SQL关键字,括号的位置,何时发明列别名,为包含两个浮点数和一个int的类创建什么列...),同时让我负责SQL的高级方面,即如何安排JOIN,服务器端计算, DISTINCT,GROUP BY,标量子查询等。

所以我写了一些做这件事的东西:http : //quince-lib.com/

它是针对C ++的:我不知道您是否使用的是这种语言,但是同样的,看到这种“中间立场”可能是有趣的。

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.