现在的位置: 首页 > 综合 > 正文

数据库性能之–iBatis延迟加载

2013年07月31日 ⁄ 综合 ⁄ 共 2180字 ⁄ 字号 评论关闭

转载于:http://zhaohe162.blog.163.com/blog/static/38216797201112122632893/?suggestedreading&wumii

 

(1)
ibatis一对多查询带来的问题:
如果在数据库中,Account记录对应着相关的多条Order记录,而Order又对应着相关的多条OrderItem记录,可以为这些记录建立关系,当我们请求一条Account记录时,可以一并获取所有的Order和OrderItem记录。下面的代码清单显示了如何定义我们的SQL映射:
 
先来看看结果映射(result map,即上面的ResultAccountInfoMap,ResultOrderInfoMap和ResultOrderItemMap),前两个Map都用到了select特性。这个特性告诉iBATIS,属性的值将由另一个映射语句来设置,语句的名称就是select特性的值。
例如,我们执行getAccountInfoList语句时,ResultAccountInfoMap结果映射有一个子元素:
 
它的作用是告诉iBATIS,account对象的orderList属性的值由ChgetOrderInfoList语句来设置,同时把accountId列的值传给ChgetOrderInfoList作为参数。
这个功能给我们带来便利的同时,也带来了两个问题。
首先,创建包含大量对象的列表可能会消耗大量的内存。
其次,这种方法会导致数据库的I/O问题,其原因是所谓的“N+1 Select”现象.
 
(2)
N+1现象:
2.1数据库I/O
数据库I/O是数据库使用状况的一项指标,也是数据库性能的主要瓶颈之一。在读取或写入数据库时,数据必须要经历从磁盘到内存或者从内存到磁盘的转换,这个过程是比较耗时的。在程序中使用缓存可以减少对数据库的访问.
2.2
在使用关联数据时,可能会遭遇数据库I/O问题(N+1现象)。考虑一下这个场景:有1000个Account,每一个关联了1000个Order,而每个Order则包含25个OrderItem。如果尝试将所有这些数据加载到内存,执行的SQL语句要超过1000000行(1条用来查询Account,1000条用于Order,1000000条用于OrderItem),而创建的对象大约为2500万——如果你真敢这么做,等你的系统管理员收拾你吧。
 
(3)
解决由关联数据查询时,引起的N+1现象,可以用延时加载。
延迟加载(Lazy loading)
首先来看看延迟加载。如果不是对所有数据都马上用到,那么延迟加载是有用的。例如,我们的程序首先在一个网页显示所有Account,然后销售代理(我们的客户)可以点击一个Account来查看该Account的Order列表,然后可以再点击一个Order来查看其所有的OrderItem信息。在这种情况下,每次都仅查询一个列表。这是对延迟加载的合理使用。
当用户 getSqlMapClientTemplate().queryForList(”getAccountInfoListN”)的时候,实际上只是执行了查询account表的信息,而当我们执行代码--在account对象中getOrderList()的时候,才会执行后面的查询orderList对象的语句;这样在首页访问 account列表的时候就不用加载orderList的信息,而在点击单个account浏览的时候需要用到orderList的时候,才会执行 getOrderList的查询操作,把列表信息给出来。这样做明显的减少了代码的负责程度,按需提取信息也提升了系统的性能!
采用延时加载,上面的xml定义,可以改为:

且须在ibatis的配置文件中定义如下:
<settings
  ……
     lazyLoadingEnabled=”true”
     enhancementEnabled=”true”
     ……/>
        lazyLoadingEnabled设置系统是否实现延迟加载机制,enhancementEnabled设置是否用字节码强制机制,通过字节码强制机制可以为lazy loadding带来性能方面的改进。
 
(4)
在加载复杂属性时可能出现两方面的问题,一是对数据库的访问,二是创建对象时对内存的消耗。我们可以采用延迟加载或Join的方法来解决这些问题,但是两者都不是万灵药。延迟加载的原理时推迟对复杂属性的加载,以减少对数据库的访问和对象的创建,但它的前提是复杂属性不会马上用到,否则的话,延迟就失去意义。Join的原理是通过一条SQL语句加载所有数据,这样可以大幅度减少对数据库的访问量,它的前提是对象的数量不会太多。该如何选择呢?下面的表格给出了简单的原则:
 
图4简单的原则
 
另外,我觉得还有一条很重要的原则,那就是永远只加载必需的数据。以上面的例子来说,我们不太可能会同时显示1000个Account给用户看,这时就不要同时加载1000个Account的数据了,可以通过分页只显示50条数据,在此基础上再应用延迟加载或Join效果会很不错。
 
(5)
结合第二章笔记,可知:
提升数据库查询性能的方式有三:
1。分页查询。(最实际有效)
2。延时加载。
3。利用cache查询(对修改次数很少的数据)。

.

抱歉!评论已关闭.