ORM选择n + 1表现;加入或不加入

时间:2009-09-02 17:39:25

标签: sql performance orm

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

情境:

客户 - 订单(订单具有客户ID) - 订单部分 - 部分

我想要一个查询,它返回一个客户及其所有订单和每个订单及其零件。

现在我有两个主要选择:

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

    关于ORM的大多数建议和示例建议使用选项2,我可以看到原因。但是,选项2可能会发回大量重复数据,例如:

    选项1结果(3个查询):

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

    选项2结果(1个查询):

    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发回13个字段,包含3个查询。选项2在1个查询中发回42个字段。现在假设Customer表有30个字段,Orders有更复杂的子连接,数据复制很快就会变得庞大。

    以下事项对整体表现有何影响:

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

    选项2总是最佳选择,选项1是最佳选择还是取决于具体情况?如果取决于,您应该使用什么标准来确定?任何ORM都能够聪明地为自己解决这个问题吗?

2 个答案:

答案 0 :(得分:7)

建立数据库连接的开销

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

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

对于SELECT N+1,这显然会更长,因为每次都必须发送select语句,这可能长达1k。它还必须从池中获取新连接。在2002-2003左右,Chatty与chunky的使用是一个争论,但现在它确实没有太大的区别,除非这是一个非常大的应用程序,在这种情况下你可能想要一个更有经验(或更好付费)的专家给出他的观点 - 即顾问。

我赞成加入,因为数据库将在10年或更长时间的开发中针对此用途进行优化。如果性能非常慢,View可以对此进行排序,或者存储过程。

顺便说一下,SELECT N+1可能是人们在第一次开始使用NHibernate时遇到的最常见的性能问题(包括我),并且实际需要调整才能解决问题。这是因为NHibernate是ORMs C ++与语言的对比。

带宽

每个SELECT的额外Customer语句最终会累积到很多Customer个对象* Orders。因此对于大型系统而言,这可能是显而易见的 - 但正如我所提到的,ORM通常具有缓存机制来抵消这个问题。考虑到SELECT语句的数量也不会那么大:

  • 大多数时候,您与SQL服务器位于同一网络上
  • 增加的字节数大约占额外0.5-50k的额外带宽?想想大多数服务器上的速度有多快。

答案 1 :(得分:4)

这很大程度上取决于您正在经历的数据量。 返回更多字段时,连接的运行速度(通常)比选项1查询集快得多。 根据我的个人经验,减速几乎总是在那个级别,即查询的实际运行,而不是你所拥有的任何管道传递的大量数据。