博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
性能优化总结(二):聚合SQL
阅读量:7231 次
发布时间:2019-06-29

本文共 2531 字,大约阅读时间需要 8 分钟。

 本篇主要讲如何使用一句较复杂的SQL来加载整个聚合对象,以达到最小化数据库连接次数。主要是解释其中的原理。

LazyLoad及其缺点

    相信越来越多的人已经开始使用富领域对象进行领域/业务层的实现了。而目前主流的数据库依然还是关系型的。这中间的转换,我们叫它ORM。ORM的设计中,有一个常用的模式叫作“延迟加载(LazyLoad)”。基设计思想大致上是说,不要把所有的数据都加载进内存,而是等到真正要使用数据的时候,再把它加载进内存。

    例如以下这个聚合对象:

    (为了和后面的代码保持一致,这里面使用的是GIX4项目中真实的类,可能会带有一些领域特性,望读者见谅。后面可能会继续使用此例,现大致对其进行解释:其中,PBSType表示一套PBS模板/类型,一套模板由许多PBS组成。PBS是Project Breakdown Structure的简称,用于对某一个项目进行分解,这里面一个PBS对象的实例其实只是结构中的一项,应该在后面加上Item,不过公司的人都习惯了,所以就延用这个命名。每个PBS有许多属性(PBSProperty),每个属性又有许多可选值(PBSPropertyOptionalValue)。)

    这个对象,在使用了LazyLoad对PBSType进行设计之后,客户程序使用代码如下:

var type = PBSType.Get(id);//do something//...//lazily load a pbs list. data access occurs.PBSList pbsList = type.PBSs;//read from memoryvar pbsListCount = type.PBSs.Count;

    这里一共产生了两次数据访问:获取PBSType对象、获取所有在该PBS模板下的PBS对象列表。此例说明了对集合对象使用LazyLoad,还有一种比较常用的LazyLoad:对引用对象的LazyLoad。如下例:

    文章对象引用一个用户对象来表示其作者。这个外键引用的关系,常常也被设计为LazyLoad。

    这一模式已经被广泛地应用在各种ORM框架中,Linq to sql、EF等。这些ORM框架极大的方便了开发者,不需要再写烦人的SQL,加快了开发效率。但是如果不谨慎使用这一模式,很可能会造成过多的数据库连接次数,导致性能低下。如果是分布式程序,则会是更耗时的远程连接。如:

IList
articles = ArticleRepository.Get(new PagerInfo(){ PageIndex = 1, PageSize = 10});foreach (var article in articles){ //LazyLoad User owner = article.Owner;}

    这段代码中一共产生了 11 次数据访问/远程连接,相当的恐怖吧!

    如何能保证又能降低连接次数,又不使用传统的Table方案呢?这就是今天要说的,一个用于重构的模式:聚合对象SQL。

 

什么是“聚合SQL”

    要支持OO的领域对象,同时保证性能,我们的ORM就需要做到:获取对象时,一次性获取它指定的关系对象(集合/引用);同时,仍然保留LazyLoad。

    例如,当我们加载上述的Article及User时,可以调用类似ArticleRepository.Get_With_User的方法,使得一次性加载Article及其对应的User。那么,数据层访问数据库时,对应的SQL应该是把所有的数据都查询出来,大致是:

select a.*, u.* 

from Articles a inner join Users u on a.UserId = u.Id

然后在把整个Table映射为Article对象列表的过程中,在每一行中读取并映射出User对象,然后对该行的Article对象的Owner属性赋值。

    对应的,集合对象的一次性加载,要完成对数据的一次性加载,生成类似以下的SQL:

select * from PBSType t

    left outer join PBS on t.Id = PBS.PBSTypeId

    在应用中,当然不会那么简单,不过都是由以上两种方式组合而成。如,在GIX4的项目PBS模块中使用到这样的一个SQL,其中关于SQL的生成及格式定义,接下来我将会做更详细的解释:

private static readonly string SQL_GET_BY_PROJECT_WITH_PROPERTY_VALUES = string.Format(@"select {0},{1},{2},{3}from ProjectPBS pp    left outer join ProjectPBSPropertyValue v on pp.Id = v.ProjectPBSId    left outer join PBSProperty p on v.PBSPropertyID = p.Id    left outer join PBSPropertyOptionalValue ov on p.Id = ov.PBSPropertyIdwhere pp.ProjectId = '{
{0}}'order by pp.Id, v.Id, p.Id", ProjectPBS.GetReadableColumnsSql("pp"), ProjectPBSPropertyValue.GetReadableColumnsSql("v"), PBSProperty.GetReadableColumnsSql("p"), PBSPropertyOptionalValue.GetReadableColumnsSql("ov"));

 本文转自BloodyAngel博客园博客,原文链接:http://www.cnblogs.com/zgynhqf/archive/2010/06/25/1765304.html,如需转载请自行联系原作者

你可能感兴趣的文章
java中map的clear和new性能对比
查看>>
macbook 备份系统
查看>>
klish 安装与使用
查看>>
Django实战(18):提交订单
查看>>
PHP时间戳函数总结
查看>>
开发自定义JSF组件(1) HelloWorld
查看>>
设计模式学习——策略模式:模拟鸭子应用
查看>>
lucene4.7 分词器(三)
查看>>
linux下让tomcat以service方式运行(及使用service tomcat start)
查看>>
HTML模版
查看>>
观察者模式摘要
查看>>
我的友情链接
查看>>
xml中单双引号
查看>>
JQuery文件上传插件JQuery.upload.js的用法简介
查看>>
Megacli 工具
查看>>
HTML5 多文件选择和FileList
查看>>
spring-boot与log4j2整合
查看>>
对函数式编程的理解
查看>>
Tomcat源码分析----一个http请求的经历
查看>>
Unix-Linux 编程实践教程 第二章 小结
查看>>