性能优化

本文介绍了减少数据库访问次数的方法,包括优化查询逻辑减少读取次数、使用页面缓存和Memcache缓存来降低数据库负担,以及利用static全局缓存对象进一步提高效率。

以下文章非原创。

1. 减少数据库读取

   首先我们来看一段代码:
  
var MyOrderList=new List<MyOrder>();//输出
var mallPayRecordList=DataAccess.MallPayrecorde.GetByPhone(Config.TuanRead, phone);//查询数据库1
foreache(var mallorder in mallPayRecordList)
{
MyOrder Order =new MyOrder ();
 Order.MallPayRecorde=mallorder ;    
Order.MallProjInfo=DataAccess.MallProjInfo.GetByAId(Config.TuanRead,mallorder.AID);//查询数据库2
 Order.PlatinumCardUser=DataAccess.PlatinumCardUser.GetByPid(Config.TuanRead,mallorder.PID);//查询数据库3
MyOrderList.Add(Order);
}

以前觉得这样写很爽,调理清晰。但是老道的程序员一眼就看出了其中是死穴,这段代码查询数据库的次数极不稳定。

分析:

如果有5条订单,就查询 1+2*5=11次。
如果有10条订单,就查询 1+2*10=21次。
如果有100条订单,就查询 1+2*100=201次。
订单一多数据库就死掉了。。。。。
 var MyOrderList=new List<MyOrder>();//输出
 var mallPayRecordList=DataAccess.MallPayrecorde.GetByPhone(Config.TuanRead, phone);//查询数据库1
 var aids=getAids(mallPayRecordList);
 var mallProjinfoList=DataAccess.MallProjInfo.GetByAIds(Config.TuanRead,aids);//查询数据库2
 var pids=getpids(mallPayRecordList);
 var  platinumCardUserList=DataAccess.PlatinumCardUser.GetByPids(Config.TuanRead,pids);//查询数据库3
          
foreache(var mallorder in mallPayRecordList)
{
  MyOrder Order =new MyOrder ();
   Order.MallPayRecorde=mallorder ;    
   Order.MallProjInfo=mallProjinfoList.FirstOrDefault(o=>o.ID==mallorder.AID);
   Order.PlatinumCardUser=platinumCardUserList.FirstOrDefault(o=>o.ID==mallorder.PID);
  MyOrderList.Add(Order);
}
我们在查询前把所有的用的MallProj和platinumCardUserList一次查出来,剩下的就在内存中操作了。优化后,无论用户有多少条订单,只需要3次查询数据库就搞定了。
 
实际体验:最原始版订单列表接口每次查询要1分钟才会出来,导致app根本无法打开。优化后3s中就打开了。
 

2. 使用页面缓存

   
    当我们把数据的查询优化到了极致时,发现某些情况下,接口还是扛不住如洪水般用户的访问,该怎么办呢?  这时候就该用到缓存了。缓存是个很好的东西,最常用的就是页面缓存,使用也很方便,一句话就搞定了。对于访问量很大,但是数据不要求实时性很高的页面,我们可以用下面语句设置页面缓存。
  
 [OutputCache(Duration = 3600, VaryByParam = "*")]

 

 
   页面输出缓存,非常高效,使用方便,真是居家旅行码农必备。
 
    效果体验:一个接口正常打开需要5s中,当设置好30分钟缓存后,第一个打开还是需要5s中,但是剩下的30分钟会在毫秒之间闪电加载,无需等待。
 
 
   但是它依然有它的短板所在,例如
    
    1.只能对整个页面加缓存,当某个页面大部分内容没有更新,而小部分内容需要实时刷新时就不好使了。
    
    2 有负载均衡的多台服务器,每台服务器用的缓存周期可能是不一样的。当我们更新了某个数据时,有的服务器更新了,有的还没更新。
 
  当页面缓存江郎才尽时,就该真正的高手Memcache登场了,请往下看:
 
 

3. Memcache缓存

     
                memcache是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发,但目前被许多网站使用以提升网站的访问速度,尤其对于一些大型的、需要频繁访问数据库的网站访问速度提升效果十分显著[1]  。这是一套开放源代码软件,以BSD license授权发布。
      
               M非常强大,它可以以键值对的形式存储各种符合要求的对象,并设置超时时间,有了它再也不用担心页面超时了。
    
               拓展阅读: http://369369.blog.51cto.com/319630/833234/
 
              使用方法如下:           
            string cacheName = Verify.GetMd5String("GetRedBagTableByCity" + city);
            var redBagListByCity = SFCCache.Get(cacheName) as DataTable;//获取缓存
            if (redBagListByCity == null || redBagListByCity.Rows.Count < 1)
            {
                redBagListByCity = ProjBuTieRules.GetRedBagListByCity(Config.ConnectionString_tuan_Read, min.City);
                SFCCache.Set(cacheName, redBagListByCity, DateTime.Now.AddMinutes(30));//加入缓存
            }        

 

            M相对于页面缓存可以多台服务器共用一套缓存,更加灵活可以以在你需要的时候拿来就用,而不用像页面缓存一样要通盘考虑是不是所有的内容都可以缓存。 
 
            使用Memcache注意事项:
 
           1. 必须是可序列化的自定义对象,才能缓存
 
           2. Datatable缓存时必须有name
 
           3.默认最大只能存储1M数据,再大了需要配置
 
 

4. static全局缓存对象(摸索体验中,尚不成熟)

    
使用页面缓存或者是Memcache可以大大减少数据库重复调用,可以大大加快接口速度,但是第一次的数据查询还是无法避免的。例如楼盘详情,全国有2W个在执行楼盘,这2w个楼盘详情每一个页面在加载时,第一次读库还是无法避免的。
 
那么有没有一种办法,可以再一次减少数据库访问呢?这就是我们要介绍的static全局缓存对象。
 
 
我们构建一个static的数组,把那些不常改变的值放到全局静态对象里面,当程序任何一个地方要用时可以直接拿来就用,而不用在去查数据,这样数据读取一次就可以一直在有效期内复用了。
 public class StaticCacheData
    {
        private  static readonly Dictionary<string, object> cacheDictionary = new Dictionary<string, object>();
 
        /// <summary>
        /// 更新静态缓存 jsxu 2016-4-27 19:42:30
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public static void Set(string key, object value)
        {
            if (cacheDictionary.ContainsKey(key))
            {
                cacheDictionary[key] = value;
            }
            else
            {
                if(cacheDictionary.Keys.Count>1000)
                {
                   //存储太多了,清空一下过期的
                   cacheDictionary.Clear();
                }
                cacheDictionary.Add(key,value);
            }
        }
 
        /// <summary>
        /// 读取静态缓存 jsxu 2016-4-27 19:42:36
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T Get<T>(string key)
        {
            if (cacheDictionary.ContainsKey(key))
            {
                return (T) cacheDictionary[key];
            }
            return default(T);
        }
 
        /// <summary>
        /// 设置缓存key jsxu 2016-4-27 19:42:40
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="minites">有效期分钟</param>
        /// <returns></returns>
        public static string GetKey(string key, int minites)
        {
            TimeSpan tspan = DateTime.Now - DateTime.Parse("2000-01-01");
            return   DateTime.Now.ToString("yyyyMMdd")+"_"+ Verify.GetMd5String(key)+"_"+ (int)(tspan.TotalMinutes/minites);
        }
    }

  

 public static List<DirectSellingProjEntity> GetDirectSellingProjList(string databaseConnectionString)
        {
            string sql = dspDao.SelectAll + " where starttime<getdate() and endtime>getdate() ";
            string cachekey = StaticCacheData.GetKey(sql, 30);
            List<DirectSellingProjEntity> list = StaticCacheData.Get<List<DirectSellingProjEntity>>(cachekey);//静态存储
            if (null == list || list.Count < 1)
            {
                list = new List<DirectSellingProjEntity>();
                DataTable table = DbHelper.Query(databaseConnectionString, sql);
                foreach (DataRow row in table.Rows)
                {
                    DirectSellingProjEntity entity = new DirectSellingProjEntity();
                    dspDao.SetBean(row, entity);
                    list.Add(entity);
                }
                StaticCacheData.Set(cachekey,list);
            }
            return list;
        }

  

转载于:https://www.cnblogs.com/panpanwelcome/p/6165155.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值