简体   繁体   English

延迟加载多对多实体时,为什么会收到N + 1个选择查询

[英]Why do I get N+1 select queries when lazy loading many-to-many entities

I expect to get only one sql query, but I run into the N+1 select trap. 我期望仅获得一个sql查询,但遇到N + 1选择陷阱。 I don't really understand why. 我真的不明白为什么。 Here is is the problem in detail: 这是详细的问题:

I have an entity "PlayerRef": 我有一个实体“ PlayerRef”:

@Entity
@Table(name = "player_ref")
public class PlayerRef {

  //constructor etc...

  @OptimisticLock(excluded = true)
  @LazyCollection(LazyCollectionOption.TRUE)
  @ManyToMany(fetch = FetchType.LAZY, mappedBy = "playerRefs")
  public Set<Player> getPlayers() {
    return players;
  }

}

And a class Player: 和一个班级球员:

@Entity
@Table(name = "player")
public class Player {

  //constructor etc...

  @OptimisticLock(excluded = true)
  @LazyCollection(LazyCollectionOption.TRUE)
  @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name="cr_player_ref_player", 
      joinColumns = {
        @JoinColumn(name="player_id", unique = true)           
      }
      ,inverseJoinColumns = {
        @JoinColumn(name="player_ref_id")
      }     
    )
  private Set<PlayerRef> getPlayerRefs() {
    return this.playerRefs;
  }
}

Now, in my program I use the following HQL query to get all playerRef entities: 现在,在我的程序中,我使用以下HQL查询来获取所有playerRef实体:

Query playerRefQ = session.createQuery("select playerRef from PlayerRef playerRef ")
  .setReadOnly(true); 
playerRefQ.setParameter("sport", sport);
@SuppressWarnings("unchecked")
List<PlayerRef> allPlayerRefs = playerRefQ.list();

This results in the N+1 Select statements: 这将导致N + 1个Select语句:

1) 1)

select
    playerref0_.id as id1_21_0_,
    ... 
from
    player_ref playerref0_ 

N times) N次)

select
    players0_.player_ref_id as player_r2_21_0_,
    players0_.player_id as player_i1_34_0_,
    player1_.id as id1_19_1_,
    ...
from
    cr_player_ref_player players0_ 
inner join
    betdata.player player1_ 
        on players0_.player_id=player1_.id 
where
    players0_.player_ref_id=?

This is (again) very unexpected, since I thought the collection is lazy loaded and the set of players of each playerRef should be a hibernate-proxy. (再次)这是非常出乎意料的,因为我认为该集合是延迟加载的,并且每个playerRef的播放器集都应该是休眠代理。

Anyone knows how I can really only load the playerRef entities without also loading the associated players? 谁知道我真的只能加载playerRef实体,而又不加载关联的玩家吗? For my use case I need all playerRefs but not the associated players. 对于我的用例,我需要所有playerRefs,但不需要关联的players。

In an earlier question of mine it was suggested, that somehow the toString() method of playerRef or Player could be overwritten in a way that references the associated entities. 在我的较早问题中,有人建议,可以某种方式引用引用关联实体的方式重写playerRef或Player的toString()方法。 This is not the case. 不是这种情况。 The N+1 queries happen right on accessing the list of all playerRef entities. N + 1查询是在访问所有playerRef实体列表时发生的。

Notes: 笔记:

  1. This is a follow up question to Why does this result in non-lazy fetching and N+1 select statements? 这是为什么会导致非延迟获取和N + 1选择语句的后续问题

  2. A similar question also without solution is here: How to lazy load a many-to-many collection in hibernate? 同样没有解决方案的类似问题在这里: 如何在休眠状态下延迟加载多对多集合?

You need to play with Batch size and the Fetch mode in order to solve that problem here is the reference link that will tell you how can you overcome the N+1 select issue 为了解决该问题,您需要使用“批处理大小”和“提取”模式,这里的参考链接将告诉您如何克服N + 1选择问题

Hope this will help 希望这会有所帮助

http://www.mkyong.com/hibernate/hibernate-fetching-strategies-examples/ http://www.mkyong.com/hibernate/hibernate-fetching-strategies-examples/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM