我不只一次听到不少做技术的朋友随口一句,“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语言性能比较的更多相关文章

  1. 开发语言性能对比,C++、Java、Python、LUA、TCC

    一直想做开发语言性能对比,刚好有时间都做了给大家参考一下, 编译类:C++和Java表现还不错 脚本类:TCC脚本动态运行C语言,性能比其他脚本快好多... 想玩TCC的同学下载测试包,TCC目录下修 ...

  2. LINQ——语言级集成查询入门指南(1)

    本文主要是对语言级集成查询或简称为LINQ做一个介绍,包括LINQ是什么,不是什么,并对它在语言特性方面做一个简短的回顾,然后举一些使用LINQ的实际例子进行说明. 语言级集成查询是什么? 在我过去写 ...

  3. C# - LINQ 语言集成查询

    LINQ(Language Integrated Query) LINQ语言集成查询是一组用于C#语言的扩展.它允许编写C#代码对数据集进行查询,比如查询内存中的对象或查询远程数据库的表.利用linq ...

  4. Go语言性能优化

    原文:http://bravenewgeek.com/so-you-wanna-go-fast/ 我曾经和很多聪明的人一起工作.我们很多人都对性能问题很痴迷,我们之前所做的是尝试逼近能够预期的(性能) ...

  5. PHP性能之语言性能优化说明

    PHP语言性能优化优化啥? 如下图所示,PHP直接执行的是opcode,所以我们尽量减少扫描和转码解析. 这是我们第一个优化点,尽量使用PHP内置的函数代替我们的代码来实现同样的功能. 和我们自己写的 ...

  6. .NET面试题系列[15] - LINQ:性能

    .NET面试题系列目录 当你使用LINQ to SQL时,请使用工具(比如LINQPad)查看系统生成的SQL语句,这会帮你发现问题可能发生在何处. 提升性能的小技巧 避免遍历整个序列 当我们仅需要一 ...

  7. 各种语言性能(CPU密集型程序)比较

    都进行Fib数列计算,计算到n=40的计算时间: 注意:开始,我以为上图中的第二列就是代表C++的性能.但是现在发现,完全不正确. 如果你使用同样的抽象和同样的逻辑去实现同样的代码,C和C++的性能几 ...

  8. Swift,Objective-C语言性能对照測试

    原文发表于踏得网 Swift包括了非常多现代语言特性尤其是从一些脚本语言如Javascript/Ruby中汲取了营养. 此外苹果公布Swift时,使用特别选用的一些样例来宣称Swift性能对于Ojbe ...

  9. PHP语言性能优化——少使用魔术方法

    对以下使用魔术方法和不适用魔术方法运行时间进行比较 使用魔术方法test1.php: <?php /** * 测试类 */ class test { private $name = " ...

随机推荐

  1. javaScript的function

    一.函数的声明方式 1.普通的函数声明 function box(num1,num2){ return num1+num2; } 2.使用变量初始化函数 var box=function(num1,n ...

  2. 【Java EE 学习 16 下】【dbutils的使用方法】

    一.为什么要使用dbutils 使用dbutils可以极大程度的简化代码书写,使得开发进度更快,效率更高 二.dbutils下载地址 http://commons.apache.org/proper/ ...

  3. python+selenium 简单尝试

    前言 selenium是一种自动化测试工具,简单来说浏览器会根据写好的测试脚本自动做一些操作. 关于自动化测试,一开始接触的是splinter,但是安装的时候发现它是基于selenium的,于是打算直 ...

  4. AngularJs ng-route路由详解

    本篇基于ng-route来讲下路由的使用...其实主要是 $routeProvider 搭配 ng-view 实现. ng-view的实现原理,基本就是根据路由的切换,动态编译html模板. 更多内容 ...

  5. ENode 1.0 - Saga的思想与实现

    开源地址:https://github.com/tangxuehua/enode 因为enode框架的思想是,一次修改只能新建或修改一个聚合根:那么,如果一个用户请求要涉及多个聚合根的新建或修改该怎么 ...

  6. thinkphp设置session有效时间

    thinkphp的框架文件 ThinkPHP/Common/functions.php function session(){ 在这个方法中找到 thinkphp .1版 if(isset($name ...

  7. 适配器模式/adapter模式/结构型模式

    定义 将类的接口转化为客户端希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作,别名Wrapper(包装器). 适配器模式,最终改变一个已有对象的接口. 使用场景 当有那么个类, ...

  8. zookeeper选举原理

    zookeeper的领导者选举和原子广播   目录:     1.工作原理概述     2.Fast Leader选举算法(领导者选举)     3.Leader与Follower同步数据(原子广播) ...

  9. 我的c++学习(10)this指针

    问题:当在对象的外部访问该对象的公有成员时,必须指明是哪一个对象.但是当我们用对象的成员函数来访问本对象的成员时,在成员函数中只要给出成员名就可以实现对该对象成员的访问.再进一步可用同一个类创建很多个 ...

  10. 【BO】安装BO服务器时,oracle服务端安装ora-12514和12541的问题

    今天在安装BO服务器,oracle数据库时,出现了这样一个问题,描述如下: 首先安装oracle10g Server 32位版.安装ORCL数据库之后,使用10gServer下的NET MANAGER ...