NHibernate性能调优之Lazy与Fetch

在应用开发中ORM(我用的是NHibernate)框架使用是否得当将直接影响到我们的程序的效率,其中的两个概念:
  • lazy懒加载
  • select N+1问题
在性能调优中起到了至关重要的作用。

在以前我个人混乱的概念里,启用懒加载时,由于关联对象要到需要的时候才查询,所以sql会被拆分成两次查询。所以为了解决select N+1问题,需要将lazy设置为false。在实际开发使用中,这混乱的概念让我吃了不少苦头。

今日仔细测试发现,事实并非如此, lazy的设置只是决定了关联信息的加载时间(一开始就加载还是需要时加载)。 而是否使用关联查询是由fetch属性决定
下面就让我们看一下lazy与fetch两个属性组合使用的效果。使用两个实体WallParam(参数)与WallParamGroup(参数组),其中关系为多对一。
     
CASE 1:将lazy设为proxy
<!-- 多对一关系 -->
< many-to-one name = " paramGroup " column = " group_id " not-null = " true " class = " Model.WallParamGroup,Model " lazy = " proxy " />
当查询WallParam信息时,lazy配置起作用了,执行的sql如下(没有同时查出WallParamGroup, 该信息被延后了):
然而当执行查询并同时获取关联的WallParamGroup信息时,nhibernate先后执行两句sql来进行查询:

结论:lazy的配置确实延后了关联信息的加载,关联信息只有被用的时候才会去数据库查询。因此查询语句也自然是拆分的sql。



CASE 2:此时已经将lazy设为false
<!-- 多对一关系 -->
< many-to-one  name = " paramGroup column = " group_id not-null = " true class = " Model.WallParamGroup,Model lazy = " false " />
当查询WallParam信息时,WallParamGroup的信息会同时加载出来。但是令人意外的是,执行的sql并不像我们认为的是一句关联查询。而是任然执行了两个拆分的sql,如下:

结论:lazy能延后关联对象的数据加载,却不能决定关联数据的获取方式(关联查询/拆分查询)。因此仅仅使用lazy属性并不能解决Select N+1问题。



CASE 3:保持lazy设为false,同时将fetch设置为join(fetch默认是“select”)
<!-- 多对一关系 -->
< many-to-one name = " paramGroup " column = " group_id " not-null = " true " class = " Model.WallParamGroup,Model " lazy = " false " fetch = " join " />
当查询WallParam信息时,WallParamGroup的信息会同时加载出来。并且从生成的sql语句看,确实使用了关联查询,一句sql就取出了所有信息:

结论:设置fetch=“join”改变了查询行为,使得关联对象能够通过join查询得到,从而解决了Select N+1问题。



CASE 4:那么fetch设置为join时,将lazy设为proxy又会有什么结果呢
<!-- 多对一关系 -->
< many-to-one name = " paramGroup " column = " group_id " not-null = " true " class = " Model.WallParamGroup,Model " lazy = " false " fetch = " join " />
当查询WallParam信息时,WallParamGroup的信息会同时加载出来(这是因为fetch指定了关联查询,所以关联的WallParamGroup 信息已经被查询出来,导致lazy失效)。并且从生成的sql语句看,确实使用了关联查询,一句sql就取出了所有信息:

结论:一旦设置fetch=“join”改变了查询行为(使用了关联查询),lazy懒加载就失去作用了(因为关联数据已经通过join查询查出)。

总结:
  • lazy设置仅仅指明了关联对象信息的加载时机(是一开始就加载,还是需要时加载)。
  • lazy加载只有在fetch=“select”(默认设置)时才有效。
  • fetch设置能够改变关联对象信息查询的行为(通过关联查询还是拆分查询)。
  • 解决Select N+1问题需要使用fetch=“join”。

所以个人认为一种合理的做法就是,实体映射是保持fetch的默认设置(select),因为只有这样才能启用懒加载。然后,当需要解决Select N+1问题以提高查询效率的时候,在程序中使用如下代码临时改变查询行为:
ICriteria.SetFetchMode("WallParamGroup", FetchMode.Join)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值