• 关于orm的个人测试——SqlSugar与FreeSql


    前言

    转眼已经过了金九,光阴真的是似箭啊,周六日常加班,忙里抽闲就想鼓捣个啥看看,刚好最近想着有没有必要换个orm,从当时原生到Dapper,又到现在的Sqlsugar,因为经常听到几个不错的orm,就是今天想测试的Freesql,其实对于造轮子这种事,个人觉得其实是件好事,只有轮子多了,才会有车,虽然参差不齐,但开车的心情还是挺嗨皮的,就算磕磕绊绊,那也是体验过才知道,当然毕竟是开源的自己也可以扩展改造嘛。

    开始

    因为电脑上只有mysql,这里就单对mysql做下对比测试了,针对增删改查这些常规操作看下性能对比(这里暂时只对sqlsugar与freesql对比,至于其他的,可以加可以加)。

    测试环境

    • net core 3.1
    • FreeSql 1.8.1
    • sqlSugarCore 5.0.0.15
    • mysql 5.5.53(wc,这么低)

    准备工作

    新建个控制台工程,引入两个nuget包FreeSqlsqlSugarCore,先来个实体吧。

    这里注意下,freesql这个库没有对应的扩展包,例如mysql还需要引入FreeSql.Provider.MySql,具体可看对应文档

        [Table(Name = "student_free")]
        [SugarTable("student_sugar")]
        public class StudentEntity
        {
            [Column(IsIdentity = true, IsPrimary = true)]
            [SugarColumn(IsIdentity = true,IsPrimaryKey = true)]
            public int ID { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }
            public string Number { get; set; }
            public int Sex { get; set; }
            public string Location { get; set; }
            [Column(Name = "class_id")]
            [SugarColumn(ColumnName = "class_id")]
            public int ClassID { get; set; }
        }
    

    接下来对应实现两个类库的方法类。

    freesql
        public class FreeSqlUtil
        {
            private static readonly string CONNECTION_STRING = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root; Initial Catalog=test;Charset=utf8;SslMode=none;Min Pool Size=20;Max Pool Size=20";
    
            private static IFreeSql _fsql;
    
            private static readonly object locker = new object();
    
            public static IFreeSql GetInstance()
            {
                if (_fsql == null)
                {
                    lock (locker)
                    {
                        if (_fsql == null)
                        {
                            _fsql = new FreeSqlBuilder()
                                    .UseConnectionString(DataType.MySql, CONNECTION_STRING)
                                    // .UseAutoSyncStructure(true)
                                    .UseLazyLoading(true)
                                    .Build();
                        }
                    }
                }
                return _fsql;
            }
        }
    

    当然这里的sql连接串记得替换成自己的。

        public class FreeSqlTest
        {
    
            public static List<StudentEntity> GetList(int index, int limit)
            {
                return FreeSqlUtil.GetInstance()
                    .Select<StudentEntity>()
                    .Page(index, limit)
                    .ToList();
            }
    
            public static List<StudentEntity> GetList(int limit)
            {
                return FreeSqlUtil.GetInstance()
                    .Select<StudentEntity>()
                    .Limit(limit)
                    .ToList();
            }
    
            public static long Insert(StudentEntity entity)
            {
                long result = FreeSqlUtil.GetInstance()
                                             .Insert(entity)
                                             .ExecuteIdentity();
                return result;
            }
    
            public static void InsertList(IEnumerable<StudentEntity> entities)
            {
                FreeSqlUtil.GetInstance()
                            .Insert(entities)
                            .ExecuteAffrows();
            }
    
            public static bool Update(StudentEntity entity)
            {
                int result = FreeSqlUtil.GetInstance()
                    .Update<StudentEntity>()
                    .SetSource(entity)
                    .ExecuteAffrows();
                return result > 0;
            }
    
            public static void UpdateList(IEnumerable<StudentEntity> entities)
            {
                FreeSqlUtil.GetInstance()
                    .Update<StudentEntity>()
                    .SetSource(entities)
                    .ExecuteAffrows();
            }
        }
    
    sqlsugar

    这里可以参考我之前文章中专门介绍sqlsugar时整理的util,当然也可以参考我的demo工程April.WebApi

        public class BaseDbContext
        {
            public SqlSugarClient Db;
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="connStr">数据库连接串</param>
            /// <param name="sqlType">数据库类型</param>
            public BaseDbContext(string connStr, int sqlType = 1)
            {
                InitDataBase(connStr, sqlType);
            }
    
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="serverIp">服务器IP</param>
            /// <param name="user">用户名</param>
            /// <param name="pass">密码</param>
            /// <param name="dataBase">数据库</param>
            public BaseDbContext(string serverIp, string user, string pass, string dataBase)
            {
                string connStr = $"server={serverIp};user id={user};password={pass};persistsecurityinfo=True;database={dataBase}";
                InitDataBase(connStr);
            }
    
            /// <summary>
            /// 初始化数据库连接
            /// </summary>
            /// <param name="listConn">连接字符串</param>
            private void InitDataBase(string connStr, int sqlType = 1)
            {
                Db = new SqlSugarClient(new ConnectionConfig()
                {
                    ConnectionString = connStr,
                    DbType = (DbType)sqlType,
                    IsAutoCloseConnection = true,
                    //SlaveConnectionConfigs = slaveConnectionConfigs
                });
                Db.Ado.CommandTimeOut = 30000;//设置超时时间
                Db.Aop.OnLogExecuted = (sql, pars) => //SQL执行完事件
                {
                    //这里可以查看执行的sql语句跟参数
                };
                Db.Aop.OnLogExecuting = (sql, pars) => //SQL执行前事件
                {
                    //这里可以查看执行的sql语句跟参数
                };
                Db.Aop.OnError = (exp) =>//执行SQL 错误事件
                {
                    //这里可以查看执行的sql语句跟参数
                };
                Db.Aop.OnExecutingChangeSql = (sql, pars) => //SQL执行前 可以修改SQL
                {
                    return new KeyValuePair<string, SugarParameter[]>(sql, pars);
                };
            }
            /// <summary>
            /// 开启事务
            /// </summary>
            public void BeginTran()
            {
                Db.Ado.BeginTran();
            }
            /// <summary>
            /// 提交事务
            /// </summary>
            public void CommitTran()
            {
                Db.Ado.CommitTran();
            }
            /// <summary>
            /// 回滚事务
            /// </summary>
            public void RollbackTran()
            {
                Db.Ado.RollbackTran();
            }
        }
    

    下面是对应的测试方法实现,其中强调一点,对于mysql中有个max_allow_packet这个配置,批量操作的时候会抛出这个异常,当然这里可以通过修改mysql的配置,不过个人建议还是尽可能通过拆解分次,应该也没有动不动甩个万八数据吧(有了轻喷),所以这里调整了插入方法的实现。

        public class SqlSugarTest
        {
            private static readonly string CONNECTION_STRING = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root; Initial Catalog=test;Charset=utf8;SslMode=none;Min Pool Size=20;Max Pool Size=20";
            private static BaseDbContext baseDb;
            private static SqlSugarClient db;
    
            static SqlSugarTest()
            {
                baseDb = new BaseDbContext(CONNECTION_STRING, 0);
                db = baseDb.Db;
            }
    
            public static List<StudentEntity> GetList(int index,int limit)
            {
                return db.Queryable<StudentEntity>().ToPageList(index, limit);
            }
            public static List<StudentEntity> GetList(int limit)
            {
                return db.Queryable<StudentEntity>().Take(limit).ToList();
            }
    
            public static int Insert(StudentEntity entity)
            {
                int result = db.Insertable(entity).ExecuteReturnIdentity();
                return result;
            }
    
            public static void InsertList(IEnumerable<StudentEntity> entities)
            {
                if (entities.Count() >= 10000)
                {
                    int count = entities.Count();
                    int index = 0;
                    Console.WriteLine($"批量插入{count}数据");
                    while (count / 5000 > 0)
                    {
                        var data = entities.Skip(5000 * index).Take(5000);
                        db.Insertable(data.ToArray())
                    .ExecuteCommand();
                        count -= 5000;
                        index++;
                    }
                    if (count % 5000 > 0)
                    {
                        var data = entities.Skip(5000 * index).Take(5000);
                        db.Insertable(data.ToArray())
                    .ExecuteCommand();
                        index++;
                    }
                    Console.WriteLine($"拆解执行{index}次");
                }
                else
                {
                    db.Insertable(entities.ToArray())
                    .ExecuteCommand();
                }
            }
    
            public static bool Update(StudentEntity entity)
            {
                int result = db.Updateable(entity).ExecuteCommand();
                return result > 0;
            }
    
            public static void UpdateList(IEnumerable<StudentEntity> entities)
            {
                if (entities.Count() >= 10000)
                {
                    int count = entities.Count();
                    int index = 0;
                    Console.WriteLine($"批量修改{count}数据");
                    while (count / 5000 > 0)
                    {
                        var data = entities.Skip(5000 * index).Take(5000);
                        db.Updateable(data.ToArray())
                    .ExecuteCommand();
                        count -= 5000;
                        index++;
                    }
                    if (count % 5000 > 0)
                    {
                        var data = entities.Skip(5000 * index).Take(5000);
                        db.Updateable(data.ToArray())
                    .ExecuteCommand();
                        index++;
                    }
                    Console.WriteLine($"拆解执行{index}次");
                }
                else
                {
                    db.Updateable(entities.ToArray())
                    .ExecuteCommand();
                }
            }
        }
    

    开始测试

    测试部分的代码就没啥发的,一个图。
    测试

    新增(下面有补充)

    新增总共测试3次吧,基本时间都是保持一个稳定的。
    新增

    新增

    新增

    查询(下面有补充)

    查询这里用的是分页方法,库里数据就是单次执行插入测试的数据,总共163006条。
    查询
    查询

    修改(下面有补充)

    修改
    修改
    修改

    补充测试

    看了下freesql入门文章,发现配置这块儿这样写,不使用命令参数化,在新增和修改的速度就很明显了,当然实际使用的时候还是要注意,毕竟注入还是可怕的。

    补充

    新增

    新增

    查询

    查询

    修改

    修改

    小结

    虽然不知道这个测试结果有没有什么问题(毕竟没咋用过),不过通过时间上来看 ,FreeSql在速度上确实是有优势,当然这里只是基础的方法测试,没有什么各种功能的尝试,不过毕竟常用的还是增删改查嘛,再鼓捣什么demo的时候可以考虑下尝试freesql了,虽然目前看来对于现工程的改动还不是太迫切,也希望轮子越来越多,越来越好,当然自己没事也会继续鼓捣,学无止境,路漫漫

  • 相关阅读:
    某开源ERP最新版SQL与RCE的审计过程
    QEMU固件模拟技术-stm32仿真分析及IRQ仿真实践
    QEMU固件模拟技术分析-luaqemu实现分析
    C/C++源码扫描系列- Fortify 篇
    C/C++源码扫描系列- Joern 篇
    C/C++源码扫描系列- codeql 篇
    bluetooth_stack开源蓝牙协议栈源码分析与漏洞挖掘
    DA14531芯片固件逆向系列(4)- L2CAP及ATT层收包再分析
    DA14531芯片固件逆向系列(3)- BLE收包流程分析及漏洞挖掘思路分享
    微服务架构简单搭建——Spring Cloud Eureka、Ribbon实现服务治理与服务消费
  • 原文地址:https://www.cnblogs.com/AprilBlank/p/13696852.html
Copyright © 2020-2023  润新知