什么是N+1问题?
在两个表存在一对一,一对多,多对一,多对多等关联信息时,查询一条数据会衍生N条查询的情况就是N+1问题。
比如两个实体类A、B。A与B数一对多,B与A是多对一。
在查询A时,会执行的语句如下:
1.从A表查找符合要求的属性,此时符合条件的数据有N条,SQL语句执行了1次。
2.对于每一条符合的数据,通过它的id去B表查关联信息,此时SQL语句执行了N次。
总计查出A和A关联的B数据共执行SQL语句N+1条
如何减少N+1
- 通过连接(内,左、右连接)解决
- JPA的配置
spring.jpa.properties.hibernate.default_batch_fetch_size=?
?为批量执行大小
原理是将之前每个sql的执行改为通过关键词in
来执行。?为in里面的个数 - @BatchSize(size=?)注解
跟JPA配置的原理一致,但@BatchSize
的使用具有局限性,不能作用于@ManyToOne
和@OneToOne
的关联关系上,只能使用在@ManyToMany
和@OneToMany
- 使用@Fetch()注解
@Fetch(FetchMode.JOIN): 始终立刻加载,使用外连(outer join)查询的同时加载关联对象,忽略FetchType.LAZY设定。
@Fetch(FetchMode.SELECT) :默认懒加载(除非设定关联属性lazy=false),当访问每一个关联对象时加载该对象,会累计产生N+1条sql语句
@Fetch(FetchMode.SUBSELECT) 默认懒加载(除非设定关联属性lazy=false),在访问第一个关联对象时加载所有的关联对象。会累计产生两条sql语句。且FetchType设定有效。