Linq语言性能比较
我不只一次听到不少做技术的朋友随口一句,“linq性能是最差的”,由于缺少具体的数字比照也就没在意,但心里隐隐觉得事实应该不是这样的,我记得我第一次听到有人贬低C# 3.0是在我工作后不久的一个夏季,天气很热,吃完晚饭有个朋友给我电话说刚在项目中用了3.0的技术,非常差劲,非常慢,我当时就觉得纳闷,不能呀,微软不可能搞出一个性能大家公认的差产品。由于当时一直关注老赵MVC beta版本技术,没太在意。其后不久开始尝试使用了EF框架,感觉没有传说中的垃圾,由于这次的尝鲜,对于net新技术就一发不可收拾地运用了起来。那时entity framework类似的技术还有一个叫linq to sql,而后不久微软合并了这两个项目,变成了统一的EF框架。首先请大家原谅我的不专业用词linq语言,我这里讨论的就是C# 3.0之后引入的linq to sql , Entity Framewokr等技术。
根据自己在社区和工作中的亲身体验来看,linq的性能一直都在提高,在最开始的两个技术版本中映射数据库的性能估计是有待提高,但在其他方面个人觉得是提高了很大的效率,当然纯个人见解,可能有很多人能罗列出一千个一万个理由否定我的观点,但我认同2点,基于这2点在项目中,乃至大型项目中运用EF框架是没有问题的。
1、比起很多大项目做到最后自定义ORM技术框架,忙于改bug和忙于升级,不与直接使用EF,在此基础上做二次优化
2、在代码量上有很大的缩减。
当然,一家之言,好了,闲话到此,进入正题,有数据和测试用例来说明linq语言、Entity Framework技术的性能。
我的环境:
硬件:Thinkpad t430 I5(2.8GHz) /8G DDR3
软件支持:Visual Studio 2012 Ultimate + MSSQL 2012
支持操作系统: Windows 8 Enterprise
一、集合操作测试
打开vs2012,创建控制台应用程序,我取的工程名为ConsoleApplication6,在program.cs文件中创建2个实体类Doc和InFast,便于做集合操作测试。
public class Doc
{
public string DocId { get; set; }
public string DocName { get; set; }
} public class InFast
{
public string DOCID { get; set; }
public string FILEPATH { get; set; }
public string MIMETYPE { get; set; }
public string ENTITYID { get; set; }
public string DOCDATETIME { get; set; }
public string EXPDATE { get; set; }
public string SUBCONTENTFORMAT { get; set; }
public string UPDATETIME { get; set; }
public string DOCTYPE { get; set; }
public string DOCCONTENTTYPE { get; set; }
public string INEFFECTIVE { get; set; }
public string STACKSTATUS { get; set; }
public string DISPLAYDOCID { get; set; }
public string Importance { get; set; }
}
创建一个9000000个元素的DOC类对象的泛型集合,分布使用传统的for循环和linq语言进行集合操作,比教性能。为了代码的整洁性,我们将这些操作封装到一个类当中,代码如下:
public class TestOperation
{
public void OperationFor()
{
List<Doc> docList = new List<Doc>();
for (int i = ; i < ; i++)
{
Doc d = new Doc();
d.DocId = Guid.NewGuid().ToString();
d.DocName = i.ToString();
docList.Add(d);
} System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start();
StringBuilder sres = new StringBuilder();
foreach (Doc d in docList)
{
sres.Append(d.DocName);
}
sw.Stop();
Console.WriteLine(string.Format("foreach take times {0}ms", sw.ElapsedMilliseconds)); sw.Restart();
StringBuilder sfor = new StringBuilder();
for (int i = ; i < docList.Count; i++)
{
sfor.Append(docList[i].DocName);
}
sw.Stop();
Console.WriteLine(string.Format("for take times {0}ms", sw.ElapsedMilliseconds)); sw.Restart();
StringBuilder smy = new StringBuilder();
docList.ForEach(p =>
{
smy.Append(p.DocName);
});
sw.Stop();
Console.WriteLine(string.Format("Linq Foreach take times {0}ms", sw.ElapsedMilliseconds)); }
在这里首先使用for循环创建了9000000个元素的List<Doc>集合,然后分别用Foreach和for循环操作集合,循环中都做了同样的事情,取出每个元素的一个对象属性的值,拼接到StringBuilder上去然后输入,在这里我们最关心的是,这两种集合操作方式各消耗的时间如何。
运行结果如下:
如此重复,我们连续测试五次查看测试结果
类别 | 第一次(ms) | 第二次(ms) | 第三次(ms) | 第四次(ms) | 第五次(ms) |
Foreach | 352 | 338 | 311 | 375 | 356 |
For | 329 | 318 | 297 | 315 | 305 |
Linq Foreach | 309 | 294 | 270 | 284 | 291 |
测试结果不言而喻,在时间消耗上linq foreach是最少的,当然如果在占用cpu和内存消耗角度而言,就需要借助第三方工具了。
二、数据库操作测试
数据库连接查询操作测试毫无疑问,首先需要有一个数据和相应的表进行测试,为了便于进行查询和插入两个操作,我们先进行插入操作比较,然后使用插入的数据进行查询操作测试。
进入MSSQL床架数据库APlatformJolAppUser,并创建表lnFastDocument,脚本如下:
create database APlatformJolAppUser
go use APlatformJolAppUser
go create table lnFastDocument
(
DOCID varchar(50) primary key not null,
FILEPATH varchar(50),
MIMETYPE varchar(50),
ENTITYID varchar(50),
DOCDATETIME datetime,
EXPDATE varchar(50),
SUBCONTENTFORMAT varchar(50),
UPDATETIME varchar(50),
DOCTYPE varchar(50),
DOCCONTENTTYPE varchar(50),
INEFFECTIVE varchar(50),
STACKSTATUS varchar(50),
DISPLAYDOCID varchar(50),
Importance varchar(50)
)
go
完成数据库和表的创建之后,进入vs,打开program.cs文件,将数据库测试操作封装一个方法OperationInsertData和OperationDatabase,将数据库的操作单独封装为一个类文件DataBase_Util.cs,这里需要使用EF,所以在完成数据库创建之后,引入Entity Framework,这里使用EF框架的Database First模式。
DataBase_Util.cs类文件主要封装了进行传统操作的SqlCommand、SqlCommand、SqlDataAdapter等对象对数据库的基本操作。代码如下:
public class DataBase_Util
{
private static string Connection_String = "Initial Catalog=APlatformJOL;User ID=sa;Password=sasasa;Data Source=.";
private SqlConnection _connection = null;
private SqlCommand _command = null; internal SqlConnection GetConnection
{
get
{
if (_connection == null)
{
_connection = new SqlConnection(Connection_String);
}
return _connection;
}
} internal SqlCommand GetCommand
{
get
{
if (_command == null)
{
_command = GetConnection.CreateCommand();
}
return _command;
}
} internal DataTable ExecSQL(string sql, params SqlParameter[] pars)
{
GetCommand.Parameters.Clear();
GetCommand.CommandText = sql;
GetCommand.CommandType = CommandType.Text;
GetCommand.Parameters.AddRange(pars); if (GetConnection.State != ConnectionState.Open)
{
GetConnection.Open();
}
DataSet ds = new DataSet();
try
{ SqlDataAdapter sda = new SqlDataAdapter(GetCommand);
sda.Fill(ds);
}
catch (Exception ex)
{
GetConnection.Close();
throw ex;
//return false;
}
GetConnection.Close();
return ds.Tables[];
} internal void ExecSQLNoRtn(string sql)
{
GetCommand.Parameters.Clear();
GetCommand.CommandText = sql;
GetCommand.CommandType = CommandType.Text; if (GetConnection.State != ConnectionState.Open)
{
GetConnection.Open();
} try
{ GetCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
GetConnection.Close();
throw ex;
//return false;
}
GetConnection.Close();
} internal bool ExecProcedure(string procName, params SqlParameter[] pars)
{
GetCommand.Parameters.Clear();
GetCommand.CommandText = procName;
GetCommand.CommandType = CommandType.StoredProcedure;
GetCommand.Parameters.AddRange(pars); if (GetConnection.State != ConnectionState.Open)
{
GetConnection.Open();
} try
{
GetCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
GetConnection.Close();
throw ex;
//return false;
}
GetConnection.Close();
return true;
} internal DataTable ExecProcedureDataTable(string procName, params SqlParameter[] pars)
{
GetCommand.Parameters.Clear();
GetCommand.CommandText = procName;
GetCommand.CommandType = CommandType.StoredProcedure;
if (pars != null)
{
GetCommand.Parameters.AddRange(pars);
}
SqlDataAdapter adapter = new SqlDataAdapter(GetCommand);
DataSet ds = new DataSet();
if (GetConnection.State != ConnectionState.Open)
{
GetConnection.Open();
} try
{
adapter.Fill(ds);
}
catch (Exception ex)
{
GetConnection.Close();
throw ex;
//return false;
}
GetConnection.Close();
return ds.Tables[];
}
}
首先创建了静态私有字段Connection_String,用于保存数据库连接字符串,Connection和Command用户数据库的操作,每次在类的实际操作函数中进行实例化和赋值。
internal DataTable ExecSQL(string sql, params SqlParameter[] pars) //带参数的sql语句执行函数,执行的sql返回datatable,取值操作
internal void ExecSQLNoRtn(string sql) //不带参数执行一段sql,典型的insert语句调用函数
internal bool ExecProcedure(string procName, params SqlParameter[] pars) //存储过程调用函数,这里暂时不会用到
再次,创建Entity Framework数据实体模型
准备工作完成之后,首先在原先的TestOperation类中再添加一个方法OperationInsertData,在这个方法中进行两个操作,第一个操作是运用传统的Sql向数据插入100000条数据,再使用EF框架插入100000条数据,比较性能。
运行结果:
连续进行5次测试:
类型 | 第一次(ms) | 第二次(ms) | 第三次(ms) | 第四次(ms) | 第五次(ms) |
SQL | 3097 | 3538 | 3371 | 3301 | 3619 |
Entity Framework | 5568 | 5440 | 5432 | 5244 | 5313 |
由此显而易见在数据的执行操作上Entity Framework的确慢了近一个级别,这不是EF的长处,但是代码量确少了不是一个级别,所以这个具体实践中看具体的项目需求,这里不做过多的论断,以免遭砖拍。
好,看完了插入操作我们再来看看关心的查询操作。同样在TestOperation类中封装查询操作的方法,方法中用传统sql和EF进行数据查询,代码如下:
public void OperationDatabase()
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
DataBase_Util dUtil = new DataBase_Util();
DataTable dtblRes = dUtil.ExecSQL("select top 90000 * from lnFastDocument");
List<InFast> fastList = new List<InFast>();
for (int i = ; i < dtblRes.Rows.Count; i++)
{
InFast fst = new InFast();
fst.DOCID = dtblRes.Rows[i]["DOCID"].ToString();
fst.FILEPATH = dtblRes.Rows[i]["FILEPATH"].ToString();
fst.MIMETYPE = dtblRes.Rows[i]["MIMETYPE"].ToString();
fst.ENTITYID = dtblRes.Rows[i]["ENTITYID"].ToString();
fst.DOCDATETIME = dtblRes.Rows[i]["DOCDATETIME"].ToString();
fst.EXPDATE = dtblRes.Rows[i]["EXPDATE"].ToString();
fastList.Add(fst);
}
sw.Stop();
Console.WriteLine(string.Format("Query the database take times {0}ms", sw.ElapsedMilliseconds)); sw.Restart();
APlatformJolAppUserEntities dbContext = new APlatformJolAppUserEntities();
var fasts = dbContext.lnFastDocuments.Take();
List<InFast> fList = from f in fasts
select new InFast {
DOCID = f.DOCID,
FILEPATH =f.FILEPATH,
MIMETYPE =f.MIMETYPE,
ENTITYID =f.ENTITYID,
DOCDATETIME =f.DOCDATETIME.ToString(),
EXPDATE =f.EXPDATE
};
sw.Stop();
Console.WriteLine(string.Format("Linq the database take times {0}ms", sw.ElapsedMilliseconds)); }
两个操作都取90000条数据,运行结果如下:
同理,测试运行5次比较性能
类型 | 第一次(ms) | 第二次(ms) | 第三次(ms) | 第四次(ms) | 第五次(ms) |
SQL | 745 | 724 | 716 | 715 | 692 |
Entity Framework | 778 | 504 | 454 | 462 | 454 |
看到这里,我想一言断之linq语言性能太差的论断确实有点操之过急啦,当然,今天我写这篇文章,可能会遭到很多人的吐槽,尤其是大数据,新兴的服务架构模式,总之,我想说的是,我并不是抬高linq语言,这里还是专业点,并不是抬高linq to sql ,Entity Framework框架,这些net新特性的价值,而是希望能正确认识微软创造出得如此神奇之作。到了今天这些其实已经算不上什么新技术,甚至有些过时,但是,我奇怪的是不能接受一门新的技术还是不能沉下来看一看代码!
很晚了,就此搁笔,有时间会继续扩充,这个话题能写的还有很多,当然,希望有这方面更好的文章出来大家一起分享。
Linq语言性能比较的更多相关文章
- 开发语言性能对比,C++、Java、Python、LUA、TCC
一直想做开发语言性能对比,刚好有时间都做了给大家参考一下, 编译类:C++和Java表现还不错 脚本类:TCC脚本动态运行C语言,性能比其他脚本快好多... 想玩TCC的同学下载测试包,TCC目录下修 ...
- LINQ——语言级集成查询入门指南(1)
本文主要是对语言级集成查询或简称为LINQ做一个介绍,包括LINQ是什么,不是什么,并对它在语言特性方面做一个简短的回顾,然后举一些使用LINQ的实际例子进行说明. 语言级集成查询是什么? 在我过去写 ...
- C# - LINQ 语言集成查询
LINQ(Language Integrated Query) LINQ语言集成查询是一组用于C#语言的扩展.它允许编写C#代码对数据集进行查询,比如查询内存中的对象或查询远程数据库的表.利用linq ...
- Go语言性能优化
原文:http://bravenewgeek.com/so-you-wanna-go-fast/ 我曾经和很多聪明的人一起工作.我们很多人都对性能问题很痴迷,我们之前所做的是尝试逼近能够预期的(性能) ...
- PHP性能之语言性能优化说明
PHP语言性能优化优化啥? 如下图所示,PHP直接执行的是opcode,所以我们尽量减少扫描和转码解析. 这是我们第一个优化点,尽量使用PHP内置的函数代替我们的代码来实现同样的功能. 和我们自己写的 ...
- .NET面试题系列[15] - LINQ:性能
.NET面试题系列目录 当你使用LINQ to SQL时,请使用工具(比如LINQPad)查看系统生成的SQL语句,这会帮你发现问题可能发生在何处. 提升性能的小技巧 避免遍历整个序列 当我们仅需要一 ...
- 各种语言性能(CPU密集型程序)比较
都进行Fib数列计算,计算到n=40的计算时间: 注意:开始,我以为上图中的第二列就是代表C++的性能.但是现在发现,完全不正确. 如果你使用同样的抽象和同样的逻辑去实现同样的代码,C和C++的性能几 ...
- Swift,Objective-C语言性能对照測试
原文发表于踏得网 Swift包括了非常多现代语言特性尤其是从一些脚本语言如Javascript/Ruby中汲取了营养. 此外苹果公布Swift时,使用特别选用的一些样例来宣称Swift性能对于Ojbe ...
- PHP语言性能优化——少使用魔术方法
对以下使用魔术方法和不适用魔术方法运行时间进行比较 使用魔术方法test1.php: <?php /** * 测试类 */ class test { private $name = " ...
随机推荐
- GD库处理图像
在PHP5中,动态图象的处理要比以前容易得多.PHP5在php.ini文件中包含了GD扩展包,只需去掉GD扩展包的相应注释就可以正常使用了.PHP5包含的GD库正是升级的GD2库,其中包含支持真彩图像 ...
- 四种常见的App弹窗设计,你有仔细注意观察吗?
弹窗又称为对话框,是App与用户进行交互的常见方式之一.弹窗分为模态弹窗和非模态弹窗两种,两者的区别在于需不需要用户对其进行回应.模态弹窗会打断用户的正常操作,要求用户必须对其进行回应,否则不能继续其 ...
- Extjs DOM操作的几个类
Extjs提供了非常完善的DOM操作方法,可以方便的操作DOM.另外Extjs还可以方便的查询DOM元素,并把这些DOM元素封装成Ext.Element对象,通过Element对象我们可以操作DOM元 ...
- ORA-01102 报错解决方法
Problem Explanation: ==================== A database is started in EXCLUSIVE mode by default. Th ...
- VMware如何实现和主机共享网络上网
VMware虚拟机的三种联网方法及原理 一.Brigde--桥接 :默认使用VMnet0 1.原理: Bridge 桥"就是一个主机,这个机器拥有两块网卡,分别处于两个局域网中,同时在& ...
- JSON和JSONP (含jQuery实例)(share)
来源:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html 前言: 说到AJAX就会不可避免的面临两个问 ...
- 【Linux】vi 命令
基本上 vi/vim 共分为三种模式,分别是一般模式.编辑模式与指令列命令模式. 这三种模式的作用分别是: 一般模式:以 vi 打开一个档案就直接进入一般模式了(这是默认的模式).在这个模式中 ...
- java比较两个对象是否相等的方法
java比较两个对象是否相等直接使用equals方法进行判断肯定是不会相同的. 例如: Person person1 =new Person("张三"); Person pe ...
- java 写一个"HelloJavaWorld你好世界"输出到操作系统文件Hello.txt文件中
package com.beiwo.homework; import java.io.File; import java.io.FileOutputStream; import java.io.IOE ...
- 浅谈iOS触摸事件理解
iOS的触摸事件个人总结,分为两步: 第一步:是找到哪个视图上触摸 第二步:分析由谁去响应(响应者连) 1.寻找被触摸的视图原理如下图 hitText:withEvent:的方法处理流程: 首先会在当 ...