• 性能优化


    以下文章非原创。

    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;
            }
    

      

  • 相关阅读:
    大数据测试2
    大数据测试3
    CROSS APPLY和 OUTER APPLY 区别详解
    SQL中的escape的用法
    Sql Server参数化查询之where in和like实现详解
    多行文本框换行符处理
    Cross Apply的用法
    交叉连接Cross Join的用法
    统计字符串中某个字符的个数
    JOIN用法
  • 原文地址:https://www.cnblogs.com/panpanwelcome/p/6165155.html
Copyright © 2020-2023  润新知