您好,欢迎来到[编程问答]网站首页   源码下载   电子书籍   软件下载   专题
当前位置:首页 >> 编程问答 >> .NET >> 提升性能 系统性能提升之道--内存镜像表

提升性能 系统性能提升之道--内存镜像表

来源:网络整理     时间:2016/8/20 8:37:02     关键词:提升性能

关于网友提出的“提升性能 系统性能提升之道--内存镜像表”问题疑问,本网通过在网上对“提升性能 系统性能提升之道--内存镜像表”有关的相关答案进行了整理,供用户进行参考,详细问题解答如下:

问题:提升性能 系统性能提升之道--内存镜像表
描述:

提出问题 
对于一个系统,我们在设计开发时,不得不考虑系统的性能问题,硬件的提速可以缓减系统日益增长的消耗,但我们也不能肆无忌惮的扩展系统而不考虑性能的提高,我们应该重视资源的有限性。 
为了说明问题,我先举个例子,有两个表如下: 
Items物料表 
字段名 
 数据类型 
 描述 
 
ID 
 Varchar(50) 
 主键(PK) 
 
Name 
 Varchar(50) 
 物料名称 
 
CatalogId 
 Varchar(50) 
 物料组ID(FK,关联Catalog表) 
 
…… 
 …. 
 ….. 
 
  
Catalog物料组表 
字段名 
 数据类型 
 描述 
 
ID 
 Varchar(50) 
 主键(PK) 
 
Name 
 Varchar(50) 
 物料名称 
 
  
物料表的CatalogId关联物料组表的主键 
要求:我们在显示物料信息时,显示此物料的物料组名称 
      传统的非ORM模式下,我们一般可以采用 
Select Items.*,Catalog.Name as “catalogName” from Items,Catalog where Items.CatalogId=Catalog.ID 
的语句来读取,然后可以在Grid上直接绑定”catalogName”来显示物料组名。这种非ORM模式开发的系统,系统扩展性非常差、数据库移植性差、开发效率低下,所以大家也都开始使用ORM的开发模式。此文章不推荐、不讲述非ORM的开发。 
      ORM模式下,我们把这两个表映射为“ItemsEntity物料实体类”与“CatalogEntity物料组实体类”。然后我们在Retrieve到一个物料对象aItem后,在显示时要求显示物料组名的话,就需要CatalogEnity去Retrieveg一个物料组对象aCatalog,使用此aCatalog的Name属性才能显示出来。 
      我们也发现了,在ORM模式下,由于采用了OO的编程模式,对开发者来说带来了很多的方便,但在过程中,进行了两次数据库访问,我们试想一下,要是此Items物料表有十个类型的外键关联,那么一个Items的显示,将进行十一次数据访问,对于极其宝贵的数据库访问资料来说,性能大打折扣了。 
  
NHibernate中的解决方案: 
在NHibernate中,可以采用“Relation”的方式来解决,需要在XML中配置十个one-to-many的“Relation”,然后采用非Lazy的方式进行一次性读取,这种方式是把十一次的数据访问放在一起执行了,这看起来可以很方便的实现;但如果有N个人都要进行这样的操作,那么数据访问数还是非常大(N*11)。而且我非常不喜欢NH里的“Relation”,因为这“Relation”还存在一个问题,返回的是对象数组,在没有Grid控件绑定的Java中,这可能是不错的方式,可是在.NET中,我们更会选择Grid进行DataTable的数据绑定,因此这种“Relation”无法很方便的返回DataTable,所以从目前来看,这种“Relation”在.NET中非常不适用的。这也是我的SPL是没有添加“Relation”的原因之一。 
  
缓存内存表的概念: 
   对于上面的这种情况,我们可以思考一下,采用另一种更好的方式解决。我们可以把这个物料组表的内容放到内存里,作为一个“内存镜像表”,此“内存镜像表”是数据库中实际表的一个镜像,实时保持与实际表的同步,我们在读取时: 
if(内存镜像存在) 
       从内存直接读取; 
else 
       { 
              从数据库读取; 
              建立内存镜像表,把数据库中的数据镜像到内存表中; 

   这样的方式可以减少很多的数据访问,就拿上面的例子中,在第一个人进行了十一次访问后,以后的N个人执行,只要执行N次数据访问了,速度将会有一个突破性的提高。 
  
内存镜像表的可行性分析: 
   对于这种“内存镜像表”的可行性我们先从数据库数据来分析。 
   一个系统将包括很多的数据,但我们可以对这些数据进行分一下类: 
   “维护性数据”: 
        这是指那些在系统中的基本维护性数据,比如前面的物料组、客户类型、付款方式、结算方式、销售类型、货币种类等等,大家都可以举出很多很多这种类似的数据,这些数据存在的共同点是: 
       数据量小:这种数据一般在50条记录以内,都是一些类型,分类之类的数据 
       字段少:这种数据的字段都是很少的,主要是ID、名称、状态等 
       使用频繁高:这种数据的使用率非常频繁,因为在其他表中作为外键,经常会被使用 
       维护少:这种数据一般在系统启用前期进行维护,大部分情况下不维护 
      因此,具有这些特点的数据,我们就非常有理由放到内存中进行缓存起来。 
“操作型数据”: 
    这种数据的特点是数据量比较大,字段也比较多,比如物料、客户等信息,不适合用到内存中。 
 “日志型数据”: 
    这种数据数据量就更多的,比如订单、订单明细、操作记录等,这就更不合适了。 
因此我们主要是考虑“维护性数据”,大家想想在你的系统中,会有多少是这种“维护性数据”,对于结构相似的“维护性数据”都会采用“数据字典”的方式来对待。 
   
内存镜像表的可操作性分析: 
在可行性分析后,我们要考虑,在实际操作起来要注意哪些。 
大家也很容易发现,唯一注意点就是“如何保持实时的镜像关系”,也就是要实时保持内存中镜像与实际的数据库表数据一致。 
那么我们就要保证在进行更新(包括新增,更新,删除)时能同时更新内存表数据就可以了。 
对于非ORM的开发模式来说,使用Sql语句进行数据访问的,要实现这种“实时同步”是很难的,幸好的是我们现在有了ORM的开发模式,在ORM上,我们的数据访问不是直接使用SQL的,而是通过中间的持久层(PersistenceLayer)来实现的,因此,这个持久层(PersistenceLayer)为实现这种同步提供了必不可少的条件。 
在OR Mapping时,我们标识一个实体为“需保存到内存镜像”,那么持久层(PersistenceLayer)在进行此对象的Save()、Update()、Delete()时,自动进行“内存同步处理”即可,而且这是完全可实现的。 
好了,我们回到前面的例子中,那样的一个物料Retrieve()操作,其实只要两次访问数据库,而且当有N个用户进行类似的操作时,由于“内存镜像表”在第一次就载入到内存了,因此访问数据库次数为N次了。 
  
内存镜像表的弊端性: 
   从上面的操作性我们就可以看出了,效率的提高是建立在内存的牺牲上的,如果有过多的“维护型数据”使用“内存镜像”,那么,整个内存消耗将非常大,所以,在考虑使用多少“内存镜像表”时,是要考虑服务器的承受能力的。 
   但我想,增加内存,提高性能这是很多客户所在追求的。因此,我们只要能仔细分析,是可以得出一种好的“内存镜像表”量的。 
  
内存镜像表的实现性: 
   这种“内存镜像表”在我的SPL(SmartPersistenceLayer)已经实现了,不知道NH等其他的持久层中是否也有类似的功能。 
   在SPL中的使用: 
在ClassMap中定义实体类的IsSaveToMemory为true即可。例: 
    
  
 
     
 
     
 
     
 
     
 
     
 
     
 
 
 
 
SPL的实现细节: 
在SPL中有个静态类,它的ArrayList里存放各种“内存镜像表”的“镜像DataTable”,在进行Retrieve()时,先判断此ArrarList中是否存在此实体的“镜像”,如果有的话,则直接从此“镜像DataTable”中Retrieve()出来,还有RetrieveCriteira(获取标准)时,会从此“镜像DataTable”中使用Select符合条件的,生成新的“镜像DataTable”返回出来。 
SPL的实体在进行Save()、Delete()和UpdateCriteria(更新标准)以及DeleteCriteria(删除标准)时都是会进行“镜像DataTable”的同步更新。 
  但这种也不能完全意义上的保证“同步”,因为SPL支持Sql语句执行,所以不要使用Sql来更新“内存镜像”的表。要不然,就无法保证“内存同步”了。 


以上介绍了“提升性能 系统性能提升之道--内存镜像表”的问题解答,希望对有需要的网友有所帮助。
本文网址链接:http://www.codes51.com/itwd/3417570.html

提升性能相关图片

提升性能相关文章