CRL4.5版本已经稳定使用于目前的几个中型项目中,在实际使用中,也发现了不少问题,这些问题都在4.52中提交

CRL具体功能和使用请浏览 CRL快速开发框架系列教程

由于现在项目是一套业务系统,查询需求比较多,CRL带的语法解析都能满足,特殊的可手写SQL,在针对查询的优化,以下几点

对查询调用的监视

由于业务封装写得非常复杂,方法嵌套很严重,无法检查一个方法内有多少查询,需不需要优化,因此使用CallContext进行了监视,并生成报表

        public ActionResult RunTime()
        {
            var str = CRL.Runtime.RunTimeService.Display();
            return Content(str);
        }

最终如下图:

路径:表示调用方法的路径

DBCall:表示实例化的数据管理类

ALLCall:表示所有数据访问调用

表达式解析内存占用

在一次更新中,为了使解析速度更快,将表达式进行了缓存,只有参数进行了重解析,看上去是省了不少,如下所示

 CRLExpression.CRLExpression BinaryExpressionHandler(Expression left, Expression right, ExpressionType expType)
var key = string.Format("{0}{1}{2}{3}", __PrefixsAllKey, left, expType, right);
var a = BinaryExpressionCache.TryGetValue(key, out cacheItem);
if (a)
  {
返回缓存
}

但是Expression left.ToString()效率并不高,并且占内存,所以这个并没有什么卵用

字符串变量内存占用

因为CRL查询所有参数都需要进行参数化,因此需要对应的参数名,如以下表达式:b=>b.Id==1

参数名为:@p1,若再有参数,依次类推,然而@p1由 string.Format("{0}p{1}","@",1)生成,在对性能测试时发现,这个Format占用了很多内存

于是解决办法,还是缓存参数名,提前生成,重复使用

if (parameDic == null)
            {
                parameDic = new Dictionary<int, string>();
                for (int i = 0; i <= 5000; i++)
                {
                    parameDic.Add(i, __DBAdapter.GetParamName("p", i));
                }
            }
var _par = parameDic[parIndex];
AddParame(_par, par);

字段格式化内存占用

CRL查询默认是查询所有字段,所以查询为 select t1.Id,t1.Name,t1.Code.....,在没有手动选择查询字段时,这些select其实一直是一样的,通过性能监视发现,好多内存被这重复解析占用了

优化后,当是查询所有字段,从缓存里生成

if (GetPrefix(__MainType) == "t1.")
            {
                key = __MainType.ToString();
                SelectFieldInfo value;
                var a = queryFieldCache.TryGetValue(key, out value);
                if (a)
                {
                    if (!cacheAllFieldString)
                    {
                        var item = value.Clone();
                        item.CleanQueryFieldString();
                        _CurrentSelectFieldCache = item;
                    }
                    else
                    {
                        _CurrentSelectFieldCache = value;
                    }
                    return;
                }
                cache = true;
            }

因为CRL对查询作了关键字处理,包括表名,字段名,所以最终的语句为

以MSSQL为例:select t1.[Name] from [table1] t1

方法为

        public override string KeyWordFormat(string value)
        {
            return string.Format("[{0}]", value);
        }

实际上,每个字段只用生成一次就行了,再次使用时从缓存中取,节省了不少内占用

        public string FieldNameFormat(Attribute.FieldAttribute field)
        {
            if (string.IsNullOrEmpty(field.MapingNameFormat))
            {
                field.MapingNameFormat = KeyWordFormat(field.MapingName);
            }
            return field.MapingNameFormat;
        }

手写语句提取参数

直接将参数拼在SQL里好像不怎么雅观,并且,容易造成语法错误和注入漏洞,如下:

string sql = "select top 10 Id,ProductId,ProductName1 from ProductData a where a.addtime>='2017-09-01' and a.id=234";
            var helper = DBExtend;
            var list = helper.ExecDynamicList(sql);

CRL新增了方法,能重新处理手写的SQL为参数化

int parIndex = 1;
        /// <summary>
        /// 提取SQL参数
        /// </summary>
        /// <param name="db"></param>
        /// <param name="sql"></param>
        /// <param name="manual"></param>
        /// <returns></returns>
        public virtual string ReplaceParameter(CoreHelper.DBHelper db,string sql,bool manual = false)
        {
            if (!SettingConfig.ReplaceSqlParameter && !manual)
            {
                return sql;
            }
            //return sql;
            var re = @"((\s|,)*)(\w+)\s*(>|<|=|!=|>=|<=)\s*('(.*?)'|([1-9]\d*.\d*|0.\d*[1-9]\d*))(\s|,|\))";
            sql = sql + " ";
            if (!Regex.IsMatch(sql, re, RegexOptions.IgnoreCase))
            {
                return sql;
            }
            Regex r = new Regex(re, RegexOptions.IgnoreCase);
            List<string> pars = new List<string>();
            //int index = 1;
            for (var m = r.Match(sql); m.Success; m = m.NextMatch())
            {
                var name = m.Groups[3];
                var op = m.Groups[4];
                var value1 = m.Groups[6];
                var value2 = m.Groups[7];
                var value = string.IsNullOrEmpty(value2.Value) ? value1 : value2;
                var p = m.Groups[1];
                var p2 = m.Groups[8];
                var pName = GetParamName("_p", parIndex);
                db.AddParam(pName, value.ToString());
                sql = sql.Replace(m.ToString(), string.Format("{0}{1}{4}{2}{3} ", p, name, pName, p2, op));
                parIndex += 1;
            }
            return sql;
        }

在配置为自动替换SQL拼接参数(CRL.SettingConfig.ReplaceSqlParameter=true),实际输出将为:

select top 10 Id,ProductId,ProductName1 from ProductData a where a.addtime>=@p1 and a.id=@p2

异步插入MSMQ的实现

在某个业务中,一张表很频繁的单个插入,占用大量资源,专门为这写个消息队列好像不怎么高明,下次又有这样的情况怎么办

于是有就了,为每个对象定义自已的消息队列和处理,用第三方的不太好集成,就是微软自家的吧

        /// <summary>
        /// 添加一条记录[基本方法]
        /// 异步时,会定时执行批量插入,依赖MSMQ服务
        /// </summary>
        /// <param name="p"></param>
        /// <param name="asyn">异步插入</param>
        public virtual void Add(TModel p, bool asyn = false)
        

调用参数为true时,则为TModel类型创建消息队列,并异步分批次插入到数据库中,比如在10秒内连续调用了100次此方法

只是将数据存入了消息队列,在队列下个处理周期,将这100条批量插入到数据库,效率倍增

DbSet方式的实现

在Entity Framework里,有DbSet的概念,配置好数据关系后,关联对象直接就能取到了

在CRL里,简单实现一下

public class Order : CRL.IModelBase
{

    public CRL.Set.DbSet<ProductData> Products//返回关联的Product
        {
            get
            {
                return GetDbSet<ProductData>(b => b.Id, ProductId);
            }
        }
        public CRL.Set.EntityRelation<Member> Member//返回关联的Member
        {
            get
            {
                return GetEntityRelation<Member>(b => b.Id, UserId);
            }
        }
}

调用如下:

var order = new Code.Order();
            //所有
            var product = order.Products.ToList();

            //返回关联过的查询,使用完整查询满足更多需求
            var product2 = order.Products.GetQuery();

            var p = new Code.ProductData() { BarCode = "33333" };
            //添加一项
            order.Products.Add(p);

            order.Products.Delete(p);//删除一项

            //返回完整的BaseProvider
            var provider = order.Products.GetProvider();

            //返回关联的member,在调用时返回,在循环内调用会多次调用数据库
            var member = order.Member.Value;

十年磨一剑,在代码写得越来越深入,再回头看自已的代码,残破不堪.

欢迎下载源码交流讨论

获取CRL最新源码见文章底部下载

CRL快速开发框架升级到4.52,谈谈开发过程中的优化的更多相关文章

  1. 非关系型数据库来了,CRL快速开发框架升级到版本4

    轮子?,我很任性,我要造不一样的轮子,同时支持关系型和非关系型的框架有没有 新版数据查询作了些调整,抽象了LabmdaQueryy和DBExtend,升级到版本4,非关系数据库MongoDB被支持了! ...

  2. CRL快速开发框架升级到3.1

    CRL是一款面向对象的轻量级ORM框架,本着快速开发,使用简便的原则,设计为 无需关心数据库结构,CRL自动维护创建,即写即用(CRL内部有表结构检查机制,保证表结构一致性) 无需第三方工具生成代理类 ...

  3. CRL快速开发框架开源完全转到Github

    CRL简介 CRL是一款面向对象的轻量级ORM框架,本着快速开发,使用简便的原则,设计为 无需关心数据库结构,CRL自动维护创建,即写即用(CRL内部有表结构检查机制,保证表结构一致性) 无需第三方工 ...

  4. CRL快速开发框架系列教程十三(嵌套查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  5. CRL快速开发框架系列教程十二(MongoDB支持)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  6. CRL快速开发框架系列教程十一(大数据分库分表解决方案)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. CRL快速开发框架系列教程十(导出对象结构)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  8. CRL快速开发框架系列教程九(导入/导出数据)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  9. CRL快速开发框架系列教程七(使用事务)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

随机推荐

  1. Django总结

    Django 中提供了开发网站经常用到的模块,常见的代码都为你写好了,通过减少重复的代码,Django 使你能够专注于 web 应用上有 趣的关键性的东西.为了达到这个目标,Django 提供了通用W ...

  2. 解决弹出蒙层滑动穿透问题-vue

    最近开发过程中遇到一些小问题(似乎问题总是那么多),但一直没什么时间去优化与解决.程序员不能被业务绑架,有时间还是花点在代码上

  3. linux服务器使用yum安装nginx

    一,安装nginx和php-fpm yum install nginx php-fpm 二, 找到nginx.conf find / -name nginx.conf 三,添加解析php配置 在ser ...

  4. 2746:约瑟夫问题poj

    2746:约瑟夫问题 总时间限制:  1000ms 内存限制:  65536kB 描述 约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退 ...

  5. 免费人脸识别APi

    今天对应一些免费的人脸识别的api 做了一下简单的对比,觉得百度开发出来的人脸识别接口还是最符合的我的要求,简单易用,容易上手. 据说百度的一些门禁也使用上了人脸识别的功能了,功能很强大,而且能识别出 ...

  6. TCP/IP 协议 ----- 协议栈

    文章是作者对tcp/ip协议族的一些看法,借鉴TCP/IP详解卷一的内容,进行总结归纳,并阐述自己的一些看法. TCP/IP协议栈· : 整个协议栈被分为了四层,每一层协议负责不同的功能: 链路层:负 ...

  7. MYSQL瓶颈

    一般来说, 在使用的时候 性能从某个数值开始.突然大大下降,说明就到了瓶颈期. mysql 瓶颈有2种,一种是 cpu瓶颈  一种是 io瓶颈.cpu瓶颈多是由io引起. 而io可以通过  show ...

  8. tensorflow 安装升级

    对于已经安装过的tensorflow,执行以下命令升级到最新版: pip3 install -U tensorflow 目前最新版本1.4

  9. webrc视频数据发送处理流程详解

  10. LDA主题模型学习笔记5:C源代码理解

    1.说明 本文对LDA原始论文的作者所提供的C代码中LDA的主要逻辑部分做凝视,原代码可在这里下载到:https://github.com/Blei-Lab/lda-c 这份代码实现论文<Lat ...