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 = " ...
随机推荐
- eclipse远程连接hive
创建项目,添加jar包,hive的s上,所以也需要hadoop的一些jar 这个图片是从网上找的,我直接使用的以前hadoop的项目 创建测试类,写测试代码 //获取jdbc链接 private ...
- php面试题2
php面试题及答案(原创)收藏 基础题: 1.表单中 get与post提交方法的区别? 答:get是发送请求HTTP协议通过url参数传递进行接收,而post是实体数据,可以通过表单提交大量信息. 2 ...
- 教你几种在SQLServer中删除重复数据方法(转)
转载地址:http://www.jb51.net/article/22980.htm 方法一 复制代码 代码如下: declare @max integer,@id integer declare c ...
- 【Java EE 学习 48】【Hibernate学习第五天】【抓取策略】【二级缓存】【HQL】
一.抓取策略. 1.hibernate中提供了三种抓取策略. (1)连接抓取(Join Fetch):这种抓取方式是默认的抓取方式.使用这种抓取方式hibernate会在select中内连接的方式获取 ...
- oracle 11g RAC安装节点二执行结果错误CRS-5005: IP Address: 192.168.1.24 is already in use in the network
[root@testdb11b ~]# /u01/app/oraInventory/orainstRoot.sh Changing permissions of /u01/app/oraInvento ...
- IBatis.Net使用总结(三)-- IBatis实现分页返回数据和总数
IBatis 分页,这里没有使用其他插件,只使用最原始的方法. 输入参数: int currentPage 当前页 int pageSize 每页大小 Hashtable findCondition ...
- webrtc的音频处理模块apm( audio processing)下载与编译出libwebrtc_audio_preprocessing.so
webrtc代码在android和chromium项目中都有.但是android中的那个带有Android.mk,稍微修改下就能用ndk-build编译出libwebrtc_audio_preproc ...
- C# 读本地INI文件方法
[DllImport("kernel32")]//加载dll private static extern int GetPrivateProfileString(string se ...
- java中采用dom4j解析xml文件
一.前言 在最近的开发中用到了dom4j来解析xml文件,以前听说过来解析xml文件的几种标准方式:但是从来的没有应用过来,所以可以在google中搜索dmo4j解析xml文件的方式,学习一下dom4 ...
- Bulk_Collect 调用方式集锦
事先申明,本文所有示例都皆源于<Expert PL SQL Practices>这本电子书的第六章.小陈觉得在学习PLSQL的过程中,将来或许会用到,在此笔记一番. 正文如下: 首先准备基 ...