关于数据执行效率

今天开发碰到了一个问题,从数据库取出一个表中的数据,大约500条左右。然后通过map转换为另外一个Model,总共用时1分钟,有时候会更多。所以,我开始怀疑automapper的执行效率。

于是,我决定写个demo看看

首先我想要先创建一个entity,和一个model

我的entity是这样的

public class TestTable
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime brithday { get; set; }
        public long Age { get; set; }
        public bool Gender { get; set; }
        public short IDTypeCode { get; set; }

        public int Id2 { get; set; }
        public string Name2 { get; set; }
        public DateTime brithday2 { get; set; }
        public long Age2 { get; set; }
        public bool Gender2 { get; set; }
        public short IDTypeCode2 { get; set; }

        public int Id3 { get; set; }
        public string Name3 { get; set; }
        public DateTime brithday3 { get; set; }
        public long Age3 { get; set; }
        public bool Gender3 { get; set; }
        public short IDTypeCode3 { get; set; }

        public int Id4 { get; set; }
        public string Name4 { get; set; }
        public DateTime brithday4 { get; set; }
        public long Age4 { get; set; }
        public bool Gender4 { get; set; }
        public short IDTypeCode4 { get; set; }

        public int Id5 { get; set; }
        public string Name5 { get; set; }
        public DateTime brithday5 { get; set; }
        public long Age5 { get; set; }
        public bool Gender5 { get; set; }
        public short IDTypeCode5 { get; set; }
}

然后我的Model和entity一样

public class TestModel2
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime brithday { get; set; }
        public long Age { get; set; }
        public bool Gender { get; set; }
        public short IDTypeCode { get; set; }

        public int Id2 { get; set; }
        public string Name2 { get; set; }
        public DateTime brithday2 { get; set; }
        public long Age2 { get; set; }
        public bool Gender2 { get; set; }
        public short IDTypeCode2 { get; set; }

        public int Id3 { get; set; }
        public string Name3 { get; set; }
        public DateTime brithday3 { get; set; }
        public long Age3 { get; set; }
        public bool Gender3 { get; set; }
        public short IDTypeCode3 { get; set; }

        public int Id4 { get; set; }
        public string Name4 { get; set; }
        public DateTime brithday4 { get; set; }
        public long Age4 { get; set; }
        public bool Gender4 { get; set; }
        public short IDTypeCode4 { get; set; }

        public int Id5 { get; set; }
        public string Name5 { get; set; }
        public DateTime brithday5 { get; set; }
        public long Age5 { get; set; }
        public bool Gender5 { get; set; }
        public short IDTypeCode5 { get; set; }
}

  

接着我需要一个可以给我生成数据的class,我写了它

public static class BuildTestData
    {
        private static T Data<T>(int? i = null)
        {
            T data = (T)Activator.CreateInstance(typeof(T));
            if (i == null)
            {
                return data;
            }
            var propertys = data.GetType().GetProperties();
            foreach (var type in propertys)
            {
                if (!type.CanWrite)
                {
                    continue;
                }
                if (type.PropertyType == typeof(int) || type.PropertyType == typeof(int?))
                {
                    type.SetValue(data, i);
                }
                else if (type.PropertyType == typeof(long) || type.PropertyType == typeof(long?))
                {
                    type.SetValue(data, Convert.ToInt64(i));
                }
                else if (type.PropertyType == typeof(bool) || type.PropertyType == typeof(bool?))
                {
                    type.SetValue(data, true);
                }
                else if (type.PropertyType == typeof(DateTime) || type.PropertyType == typeof(DateTime?))
                {
                    type.SetValue(data, DateTime.Now);
                }
                else if (type.PropertyType == typeof(string))
                {
                    string value = "test" + type.Name + i;
                    type.SetValue(data, value);
                }
            }
            return data;
        }

        public static T CreateData<T>(this T obj)
        {
            return Data<T>(1);
        }

        public static List<T> CreateData<T>(this List<T> obj, int size, bool isAddNull = false)
        {
            obj = new List<T>();
            for (int i = 1; i <= size; i++)
            {
                var data = Data<T>(i);
                obj.Add(data);
            }
            if (isAddNull)
            {
                obj.Add(Data<T>());
            }
            return obj;
        }

}

然后分别使用for、foreach和automapper转换为TestModel2

for:

public List<TestModel2> ValidationFor(List<TestTable> list)
        {
            List<TestModel2> list2 = new List<TestModel2>();
            for (int i = 0; i < list.Count; i++)
            {
                list2.Add(new TestModel2()
                {
                    Id = list[i].Id,
                    Name = list[i].Name,
                    brithday = list[i].brithday,
                    Age = list[i].Age,
                    Gender = list[i].Gender,
                    IDTypeCode = list[i].IDTypeCode,
                    Id2 = list[i].Id,
                    Name2 = list[i].Name,
                    brithday2 = list[i].brithday,
                    Age2 = list[i].Age,
                    Gender2 = list[i].Gender,
                    IDTypeCode2 = list[i].IDTypeCode,
                    Id3 = list[i].Id,
                    Name3 = list[i].Name,
                    brithday3 = list[i].brithday,
                    Age3 = list[i].Age,
                    Gender3 = list[i].Gender,
                    IDTypeCode3 = list[i].IDTypeCode,
                    Id4 = list[i].Id,
                    Name4 = list[i].Name,
                    brithday4 = list[i].brithday,
                    Age4 = list[i].Age,
                    Gender4 = list[i].Gender,
                    IDTypeCode4 = list[i].IDTypeCode,
                    Id5 = list[i].Id,
                    Name5 = list[i].Name,
                    brithday5 = list[i].brithday,
                    Age5 = list[i].Age,
                    Gender5 = list[i].Gender,
                    IDTypeCode5 = list[i].IDTypeCode,
                });
            }
            return list2;
        }

Foreach:

public List<TestModel2> ValidationForeach(List<TestTable> list)
        {
            List<TestModel2> list2 = new List<TestModel2>();
            foreach (var item in list)
            {
                list2.Add(new TestModel2()
                {
                    Id = item.Id,
                    Name = item.Name,
                    brithday = item.brithday,
                    Age = item.Age,
                    Gender = item.Gender,
                    IDTypeCode = item.IDTypeCode,
                    Id2 = item.Id,
                    Name2 = item.Name,
                    brithday2 = item.brithday,
                    Age2 = item.Age,
                    Gender2 = item.Gender,
                    IDTypeCode2 = item.IDTypeCode,
                    Id3 = item.Id,
                    Name3 = item.Name,
                    brithday3 = item.brithday,
                    Age3 = item.Age,
                    Gender3 = item.Gender,
                    IDTypeCode3 = item.IDTypeCode,
                    Id4 = item.Id,
                    Name4 = item.Name,
                    brithday4 = item.brithday,
                    Age4 = item.Age,
                    Gender4 = item.Gender,
                    IDTypeCode4 = item.IDTypeCode,
                    Id5 = item.Id,
                    Name5 = item.Name,
                    brithday5 = item.brithday,
                    Age5 = item.Age,
                    Gender5 = item.Gender,
                    IDTypeCode5 = item.IDTypeCode,
                });
            }
            return list2;
        }

Automapper(不得不说map可以省很多事)

public List<TestModel2> ValidationAutoMapper(List<TestTable> list)
        {
            //this.CreateMap<List<TestModel>, List<TestModel2>>();

            Mapper.Initialize(cfg => cfg.CreateMap<List<TestTable>, List<TestModel2>>());
            //or
            var config = new MapperConfiguration(cfg => cfg.CreateMap<List<TestTable>, List<TestModel2>>());
            var result = Mapper.Map<List<TestTable>, List<TestModel2>>(list);
            return result;
        }

然后我用我生成数据的类,生成了十万条数据

public static List<TestTable> list = new List<TestTable>();
list = list.CreateData(100000);

然后使用Stopwatch 测试执行时间

Program pa = new Program();
            Stopwatch stopTime = new Stopwatch();
            //pa.CreateEfData();
            Log log = new Log();
            list = list.CreateData(100000);
            //list2 = list2.CreateData(100000);
            stopTime.Start();
            pa.ValidationFor(list);
            stopTime.Stop();
            TimeSpan ts = TimeSpan.FromMilliseconds(stopTime.ElapsedMilliseconds);
            string str = string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
            log.log("for:" + str);
            Console.WriteLine("for:" + str);
            stopTime.Reset();

            stopTime.Start();
            pa.ValidationForeach(list);
            stopTime.Stop();
            TimeSpan ts2 = TimeSpan.FromMilliseconds(stopTime.ElapsedMilliseconds);
            string str2 = string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", ts2.Hours, ts2.Minutes, ts2.Seconds, ts2.Milliseconds);
            log.log("foreach:" + str2);
            Console.WriteLine("foreach:" + str2);
            stopTime.Reset();

            stopTime.Start();
            pa.ValidationAutoMapper(list);
            stopTime.Stop();
            TimeSpan ts3 = TimeSpan.FromMilliseconds(stopTime.ElapsedMilliseconds);
            string str3 = string.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", ts3.Hours, ts3.Minutes, ts3.Seconds, ts3.Milliseconds);
            log.log("automapper:" + str3);
            Console.WriteLine("automapper:" + str3);
            stopTime.Reset();

            Console.ReadLine();

运行结果:

可以得出这样一个结论

Foreach是最快的一个,其次是for,再接着就是automapper,automapper是for和foreach的整整两倍。

可是,就算是这样,我500条数据map为什么会用了1分钟呢?难道是因为数据库?

我在数据库中又接着创建了这样一张表

--create table TestTable
--(
--    Id int identity(1,1) primary key,
--    Name nvarchar(100),
--    brithday datetime,
--    Age bigint,
--    Gender bit,
--    IDTypeCode smallint,

--    Id2 int ,
--    Name2 nvarchar(100),
--    brithday2 datetime,
--    Age2 bigint,
--    Gender2 bit,
--    IDTypeCode2 smallint,

--    Id3 int  ,
--    Name3 nvarchar(100),
--    brithday3 datetime,
--    Age3 bigint,
--    Gender3 bit,
--    IDTypeCode3 smallint,

--    Id4 int,
--    Name4 nvarchar(100),
--    brithday4 datetime,
--    Age4 bigint,
--    Gender4 bit,
--    IDTypeCode4 smallint,

--    Id5 int,
--    Name5 nvarchar(100),
--    brithday5 datetime,
--    Age5 bigint,
--    Gender5 bit,
--    IDTypeCode5 smallint,
--)

添加了6万条数据

通过sql取得数据

public void CreateSqlData()
        {
            using (SqlConnection con = new SqlConnection("*****"))
            {
                con.Open();
                SqlCommand com = new SqlCommand();
                com.Connection = con;
                com.CommandText = "select Id, Name, brithday, Age, Gender, IDTypeCode, Id2, Name2, brithday2, Age2, Gender2, IDTypeCode2, Id3, Name3, brithday3, Age3, Gender3, IDTypeCode3, Id4, Name4, brithday4, Age4, Gender4, IDTypeCode4, Id5, Name5, brithday5, Age5, Gender5, IDTypeCode5 from TestTable";
                com.CommandType = System.Data.CommandType.Text;
                using (SqlDataReader read = com.ExecuteReader())
                {
                    while (read.Read())
                    {
                        list.Add(new TestTable()
                        {
                            Id = Convert.ToInt32(read["Id"]),
                            Name = read["Name"].ToString(),
                            brithday = Convert.ToDateTime(read["brithday"]),
                            Age = Convert.ToInt64(read["Age"]),
                            Gender = Convert.ToBoolean(read["Gender"]),
                            IDTypeCode = Convert.ToInt16(read["IDTypeCode"]),

                            Id2 = Convert.ToInt32(read["Id2"]),
                            Name2 = read["Name2"].ToString(),
                            brithday2 = Convert.ToDateTime(read["brithday2"]),
                            Age2 = Convert.ToInt64(read["Age2"]),
                            Gender2 = Convert.ToBoolean(read["Gender2"]),
                            IDTypeCode2 = Convert.ToInt16(read["IDTypeCode2"]),

                            Id3 = Convert.ToInt32(read["Id3"]),
                            Name3 = read["Name3"].ToString(),
                            brithday3 = Convert.ToDateTime(read["brithday3"]),
                            Age3 = Convert.ToInt64(read["Age3"]),
                            Gender3 = Convert.ToBoolean(read["Gender3"]),
                            IDTypeCode3 = Convert.ToInt16(read["IDTypeCode3"]),

                            Id4 = Convert.ToInt32(read["Id4"]),
                            Name4 = read["Name4"].ToString(),
                            brithday4 = Convert.ToDateTime(read["brithday4"]),
                            Age4 = Convert.ToInt64(read["Age4"]),
                            Gender4 = Convert.ToBoolean(read["Gender4"]),
                            IDTypeCode4 = Convert.ToInt16(read["IDTypeCode4"]),

                            Id5 = Convert.ToInt32(read["Id5"]),
                            Name5 = read["Name5"].ToString(),
                            brithday5 = Convert.ToDateTime(read["brithday5"]),
                            Age5 = Convert.ToInt64(read["Age5"]),
                            Gender5 = Convert.ToBoolean(read["Gender5"]),
                            IDTypeCode5 = Convert.ToInt16(read["IDTypeCode5"]),
                        });
                    }
                }
            }
        }

结果

这下最快的变成了for,其次是foreach、最后automapper,可以发现automapper已经慢的b不止一个层次的问题了。

那么,如果我把取数据的地方换成ef呢?

首先是配置

public class MyEntities : IdentityDbContext<IdentityUser>
    {
        public MyEntities() : base("TestDb")
        {
            Database.SetInitializer<MyEntities>(null);
        }
        public DbSet<TestTable> TestTable { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            base.OnModelCreating(modelBuilder);
        }
}

使用ef取得数据

public void CreateEfData()
        {
            MyEntities myTest = new MyEntities();
            var demo = from c in myTest.TestTable
                       select c;
            list = demo.ToList();
        }

结果

神奇的事情发生了有没有,automapper居然又恢复到了100毫秒,难道ef对automapper有帮助吗?

可问题依然没有得到解决,我想知道的是,为什么我的map只有500条数据却用了1分钟,让我很纠结

于是我仔细的看的entity

忽然有两行代码引起了我的注意

[ForeignKey("AId")]
        public virtual ATable ATable { get; set; }

        [ForeignKey("BId")]
        public virtual BTable BTable { get; set; }

会不会是因为表关系?

我把map删掉后换成了foreach,

AName = c.ATable == null ? string.Empty : c.ATable.Name,
BName = c.BTable == null ? string.Empty : c.BTable.Name,

运行结果

58秒(XD快了几秒)

那如果我把这两行代码删掉呢?

奇迹发生了,15秒!!!

果然,是这两个表关系搞得鬼,紧接着,我就把代码做了优化

先把数据取出来,然后再进行赋值

var aName = string.Empty;
            var bName = string.Empty;
            if (aList != null && aList.Count > 0)
            {
                aName = aList.FirstOrDefault(s => s.Id == item.AId).Name;
            }
            if (bList != null && bList.Count > 0)
            {
                bName = bList.FirstOrDefault(s => s.Id == item.BId).Name;
            }

            AName = aName
            BName = bName

运行结果 18秒XD~

问题终于得到了解决

可是,话又说回来,ef通过virtual 取出来的关系数据效率有这么差吗?

还是这个地方有别的什么可以优化的地方吗?

这个问题还需要深究。

时间: 2024-10-13 17:07:14

关于数据执行效率的相关文章

如何在数据访问层上提高js的执行效率

本文讲到的是如何从数据访问层面上提高JS 代码的执行效率.总的来讲有以下几条原则: 函数中读写局部变量总是最快的,而全局变量的读取则是最慢的: 尽可能地少用with 语句,因为它会增加with 语句以外的数据的访问代价: 闭包尽管强大,但不可滥用,否则会影响到执行速度以及内存: 嵌套的对象成员会明显影响性能,尽量少用: 避免多次访问对象成员或函数中的全局变量,尽量将它们赋值给局部变量以缓存. 这么几句话看似简单,但要深刻理解其中的道理则需涉及到JS的 标识符解析.作用域链.运行期上下文(又称为执

简单十招提高jQuery执行效率

1. 使用最新版本的jQuery jQuery的版本更新很快,你应该总是使用最新的版本.因为新版本会改进性能,还有很多新功能. 下面就来看看,不同版本的jQuery性能差异有多大.这里是三条最常见的jQuery选择语句: $('.elem') $('.elem', context) context.find('.elem') 我们用1.4.2.1.4.4.1.6.2三个版本的jQuery测试,看看浏览器在1秒内能够执行多少次.结果如下: 可以看到,1.6.2版本的运行次数,远远超过两个老版本.尤

参数探测(Parameter Sniffing)影响存储过程执行效率

如果SQL query中有参数,SQL Server 会创建一个参数嗅探进程以提高执行性能.该计划通常是最好的并被保存以重复利用.只是偶尔,不会选择最优的执行计划而影响执行效率. SQL Server尝试通过创建编译执行计划来优化你的存储过程的执行.通常是在第一次执行存储过程时候会生成并缓存查询执行计划.当SQL Server数据库引擎编译存储过程中侦测到有参数值传递进来的时候,会创建基于这些参数的执行计划.这种在编译存储过程中侦测参数值的方法,通常被称为"参数探测".有时参数探测会产

in和exists的区别与SQL执行效率

in和exists的区别与SQL执行效率最近很多论坛又开始讨论in和exists的区别与SQL执行效率的问题,本文特整理一些in和exists的区别与SQL执行效率分析 SQL中in可以分为三类: 1.形如select * from t1 where f1 in ('a','b'),应该和以下两种比较效率 select * from t1 where f1='a' or f1='b' 或者 select * from t1 where f1 ='a' union all select * fro

解决 C++ 操作 MySQL 大量数据插入效率低下问题

往 Mysql 中,插入10000条简单数据,速度非常缓慢,居然要5分钟左右, 但是打开事务的话,一秒不到就搞定了 代码: #include <iostream> #include <winsock2.h> #include <string> #include "mysql.h" #pragma comment(lib, "libmysql.lib"); using namespace std; int main() { MYSQ

SQL Server 并行操作优化,避免并行操作被抑制而影响SQL的执行效率

为什么我也要说SQL Server的并行: 这几天园子里写关于SQL Server并行的文章很多,不管怎么样,都让人对并行操作有了更深刻的认识. 我想说的是:尽管并行操作可能(并不是一定)存在这样或者那样的问题,但是我们不能否认并行,仍然要利用好并行. 但是,实际开发中,某些SQL语句的写法会导致用不到并行,从而影响到SQL的执行效率 所以,本文要表达的是:我们要利用好并行,不要让一些SQL的写法问题“抑制”了并行,让我们享受不了并行带来的快感 关于SQL Server的并行: 所谓的并行,指S

30条技巧提高Web程序执行效率

尽量避免使用DOM.当需要反复使用DOM时,先把对DOM的引用存到JavaScript本地变量里再使用.使用设置innerHTML的方法来替换document.createElement/appendChild()方 法. eval()有问题,new Fuction()构造函数也是,尽量避免使用它们. 拒绝使用with语句. 它会导致当你引用这个变量时去额外的搜索这样的一个命名空间,with里的代码在编译时期是完全未知的. 使用for()循环替代for…in循 环.因为for…in循环在开始循环

linux下安装eaccelerator加速php执行效率

说明:php安装目录:/usr/local/php5php.ini配置文件路径:/usr/local/php5/etc/php.iniNginx安装目录:/usr/local/nginxNginx网站根目录:/usr/local/nginx/html安装篇1.安装编译工具 yum -y install php-devel autoconf automake m4 libtool 2.安装eacceleratorcd /usr/local/src  #进入软件包存放目录wget http://ac

sql语句or与union all的执行效率比较

看到一篇文章是讲sql语句or与union all的执行效率比较的,以前没怎么注意这个问题,感觉文章写的不错,转来一看. 文章原链接:http://www.cunyoulu.com/zhuanti/qtstudy/20081124orunion.htm sql语句or与union all的执行效率比较 当SQL语句有多个or语句时,可以考虑使用union或者union all代替来提高速度.使用or的SQL语句往往无法进行优化,导致速度变慢.但这不是固定的,有时候使用or速度会更快些.具体情况还