Hibernate中FetchMode.SELECT搭配FetchType.EAGER与FetchMode.JOIN的性能差异及相关问题咨询
Hibernate中FetchMode.SELECT搭配FetchType.EAGER与FetchMode.JOIN的性能差异及相关问题咨询
咱们结合你的Page和Comment关联场景,逐个拆解你的问题:
一、FetchMode.SELECT + FetchType.EAGER 与 FetchMode.JOIN 的性能差异
先明确两者的执行逻辑,再谈性能:
- FetchMode.JOIN:Hibernate会生成一条左连接SQL,一次性拉取所有符合条件的Page及其关联的Comment。比如你要分页查5个Page,这条SQL会返回所有这5个Page的Comment对应的记录(每个Comment对应一条带Page数据的行),之后Hibernate会自动合并重复的Page实体。
性能特点:单条查询,避免了多次数据库往返,但如果每个Page的Comment数量多,结果集体积会很大,传输和内存处理的开销会上升;这也是你遇到分页问题的原因——分页是对连接后的总结果集生效,而非Page的数量,导致没法拿到预期的5个Page。 - FetchMode.SELECT + FetchType.EAGER:Hibernate会先执行1次查询获取目标Page列表(比如分页的5个),然后为每个Page单独执行1次查询获取它的Comment。
性能特点:多次数据库查询(1+N次,N为Page的数量),每次查询的结果集小,但多次往返数据库会带来额外开销。如果Page数量少,差异不大;但如果Page数量多,这种方式的性能会明显下降。
二、FetchMode.SELECT + FetchType.EAGER 会触发N+1查询问题吗?
答案是肯定会,这就是标准的N+1场景:
- 当你加载Page集合时,首先执行1次SQL查询所有符合条件的Page(这是“1”);
- 因为设置了FetchType.EAGER,Hibernate会立即为每个Page单独执行1次SQL查询对应的Comment(这是“N”次,N等于加载的Page数量);
- 举个例子:你分页查5个Page,总共会执行1+5=6次查询,这就是典型的N+1问题。
三、设置Batch Size对FetchMode.SELECT + FetchType.EAGER有效吗?
当然有效,这是解决上述N+1问题的常用优化手段!
你只需要在Comment的@ManyToOne字段(或者Page的@OneToMany集合)上添加@BatchSize(size = 10)(size值可根据业务调整),Hibernate就会优化查询逻辑:
- 先执行1次查询获取所有Page;
- 然后一次性执行1次批量查询,用
in条件传入所有Page的id,比如执行select * from comment where page_id in (1,2,3,4,5),一次性拉取所有这些Page的Comment; - 这样原本的1+N次查询就变成了1+1次,大幅减少数据库往返次数,性能提升很显著。
备注:内容来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

