当前位置: 首页 > 面试题库 >

ORM选择n + 1个性能;加入或不加入

松钊
2023-03-14
问题内容

也有类似的问题,但我认为没有人问过这个特定问题。

设想:

客户-订单(其中订单具有客户ID)-OrderPart-部件

我想要一个查询,该查询返回具有其所有订单以及每个订单及其零件的客户。

现在,我有两个主要选择:

  1. 使用嵌套循环(产生单独的查询)
  2. 使用数据加载选项(产生单个查询联接)

问题:

关于ORM的大多数建议和示例都建议使用选项2,我可以理解为什么。但是,选项2可能会发送回大量重复的数据,例如:

Option 1 results (3 queries):

ID  Name       Country
1   Customer1  UK

ID  Name
1   Order1
2   Order2

ID  Name
1   Part1
2   Part2
3   Part3

Option 2 results (1 query):

ID  Name       Country  ID  Name    ID Name
1   Customer1  UK       1   Order1  1  Part1
1   Customer1  UK       1   Order1  2  Part2
1   Customer1  UK       1   Order1  3  Part3
1   Customer1  UK       2   Order2  1  Part1
1   Customer1  UK       2   Order2  2  Part2

选项1发送带有3个查询的13个字段。选项2在1个查询中发回42个字段。现在,假设客户表有30个字段,而订单具有更复杂的子联接,则数据重复会迅速变得庞大。

以下各项会对整体性能产生什么影响:

  • 建立数据库连接的开销
  • 发送数据所花费的时间(如果在其他服务器上,则可能跨网络)
  • 带宽

选项2始终是最佳选择,选项1是最佳选择还是取决于情况?如果需要,应使用什么标准来确定?是否有足够的ORM聪明地自己解决?


问题答案:

建立数据库连接的开销

如果它们位于通常的同一子网中,则很少。如果不是,那么这仍然不是很大的开销,可以通过大多数ORM拥有的缓存来克服(NHibernate具有第一级和第二级缓存)。

发送数据所花费的时间(如果在其他服务器上,则可能跨网络)

因为SELECT N+1这显然会更长,因为每次都必须发送select语句,最长可能长达1k。它还必须从池中获取新的连接。在2002年至2003年间,使用Chatty和矮胖的说法一直是争论的焦点,但是除非这是一个非常大的应用程序,否则现在并没有太大的不同,在这种情况下,您可能希望有经验的(或薪水更高的)专家来发表他的观点。
-即顾问。

但是,我希望加入连接,因为数据库将在其10或10多年的开发过程中针对这种用法进行优化。如果性能确实很慢,则View可以解决此问题或存储过程。

顺便说一句,SELECT N+1这可能是人们在首次使用NHibernate时(包括我自己)遇到的最常见的性能问题,而这实际上是需要进行调整才能解决的。这是因为NHibernate对ORM而言就像C
++对语言一样。

带宽

SELECT每个对象的额外语句Customer最终将建立许多Customer对象* Orders。因此,对于大型系统而言,这可能很明显-
但正如我提到的那样,ORM通常具有适当的缓存机制来消除此问题。SELECT考虑到以下事实,语句的数量也不会那么大:

  • 大多数情况下,您与SQL Server处于同一网络上
  • 增加的字节数大约会带来额外的0.5-50k的额外带宽?想一想大多数服务器上的速度有多快。


 类似资料:
  • 问题内容: 几个月前,我和其他人一起用PHP编写了一个简单的应用程序。在那里,我们需要根据一个用户ID和您需要从该用户ID选择的行中获取的另一个值,从多个表中执行SELECT。 我的第一个想法是创建多个SELECT并解析PHP脚本中的所有输出(使用所有mysql_num_rows()和类似的函数进行检查),但是那个家伙告诉我他会这样做。“好的没问题!” 我想,我的写作要少得多。好吧,当我发现他只用

  • 问题内容: 我有以下型号: 我想查询所有未分配志愿者的部门。我可以使用以下查询进行操作: 有没有一种更像django的方式做到这一点,还是我应该只使用原始sql? 问题答案: 您可以通过遵循查找中的向后关系来执行此操作。 以下是有关“跨多值关系”查询的文档:https : //docs.djangoproject.com/en/stable/topics/db/queries/#spanning-

  • 问题内容: 我有3张桌子: 我想显示所有车辆名称的列表。如果,也应返回。 所以我想我将从这里开始: 返回以下内容: 但是,我现在无法将其范围缩小到所需的结果。如果使用,则没有任何变化,因为我已经在JOIN之前选择了不同的汽车ID。加入后它们才是唯一的。如果使用,则删除最后两行,所有对货车的引用都消失了。如果使用,则将第一行和最后一行合并,但是摩托车的则是任意选择的。我想要的是: 我需要一个唯一的汽

  • 我有3个表格:我的Laravel 5项目的产出、产品和服务。 我想基于此条件在一个查询中连接这3个表: 如果(p=产品)获取products.name 如果(s=服务)获取服务。名称

  • 我想在SQL中执行以下操作: 在jOOQ中,我将subQ存储到Select中 我的问题是,如何从subQ中获取maxCol列,并在join中使用它?我的连接是这样的: 我在()上出错 类型字段中的方法eq(字符串)不适用于参数(字段) 我该怎么办?

  • 我有一个java应用程序,它有三个“形上说”的对象。。。1类动物,1类食物,这些与任何遗传或接口无关。。班级经理的最后一个任务是列出动物和食物的清单,经理负责动物园里的动物和食物。。 说到点子上。。。 我正在使用log4j,我需要登录到一个txt文件,如果并且仅当动物列表中的某些内容发生变化。。。(动物死了,出生了,或者什么的…)我需要登录系统。当且仅当食物清单中的某些东西发生变化时。。。(需要新