Lostinet

Lostinet
随笔 - 18, 文章 - 0, 评论 - 297, 引用 - 4
数据加载中……

IbatisMapping,Linq2SQL,RuntimeEntity,到底哪个最快 ? (更新,提供对比IBatis的VS2005工程下载 )

在看完下面的文章之前, 希望读者心里估计一下大概的情况.
也许文章里所归纳的结论, 和你想的相差非常远.
更新,提供对比IBatis的VS2005工程下载 :
http://files.cnblogs.com/Lostinet/RuntimeEntityVSIBatisMapping.rar


以下测试都比较单调.  实际情况会根据数据表格式的不同,返回的记录数不同等各种情况下有偏差. 但下这些测试结果,总能说明一些问题的.


Linq To SQL 篇:

以下分别是RuntimeEntity和Linq2SQL,使用Lambda表达式构造SQL进行查询的C#语句和对应的SQL语句 , price=10 , city="London" :

RuntimeEntity:

for (int i = 0; i < repeattime; i++)
{
    RuntimeEntity.All
<Product>().WhereSql(p => p.UnitPrice > price && p.Supplier.City == city).LoadReaderArray();
}
exec sp_executesql N'SELECT [ProductID],[ProductName],[SupplierID],[CategoryID],[QuantityPerUnit],[UnitPrice],[UnitsInStock],[UnitsOnOrder],[ReorderLevel],[Discontinued] FROM [Products]
 WHERE ([UnitPrice]>@p0_0) AND ((SELECT [T-Suppliers].[City] FROM [Suppliers] AS [T-Suppliers] WHERE [T-Suppliers].[SupplierID]=[Products].[SupplierID])=@p0_1)
', N'@p0_0 decimal(2,0),@p0_1 nvarchar(100)'@p0_0 = 10@p0_1 = N'London'


Linq To SQL:

using (LinqNorthwind.NorthwindContext nc = new LinqNorthwind.NorthwindContext(connectionstring))
{
    
for (int i = 0; i < repeattime; i++)
    {
        nc.Products.Where(p 
=> p.UnitPrice > price && p.Supplier.City == city).ToArray();
    }
}
exec sp_executesql N'SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]
FROM [dbo].[Products] AS [t0]
LEFT OUTER JOIN [dbo].[Suppliers] AS [t1] ON [t1].[SupplierID] = [t0].[SupplierID]
WHERE ([t0].[UnitPrice] > @p0) AND ([t1].[City] = @p1)
', N'@p0 money,@p1 nvarchar(6)'@p0 = $10.0000@p1 = N'London'


这些SQL都是返回2条记录. 循环5000次后, 得出的结果是:

RuntimeEntity 4.528秒
Linq To SQL  44.514秒

这个结果差异实在太大了. Linq2SQL竟然慢10倍, 我也觉得很惊讶.

如果把&& p.Supplier.City == city去掉 , 那么一次查询是返回63条记录, 消耗的时间则是

RuntimeEntity 5.168秒
Linq To SQL  28.819秒
(估计DLinq生成SQL比较满.所以取消跨表的条件后变快了)

如果把条件换成 p => p.ProductID<3 强制简单的条件,并且返回2条记录,消耗的时间则是

RuntimeEntity 1.052
Linq To SQL  10.627

我也测试过其他情况, 修改条件,调整一下记录数 , 总的说来, 性能差异保持在 5-10 倍之间.

 


IbatisMapping篇:

与Ibatis的对比测试是SELECT所有Orders (830条记录) 循环500次.

RuntimeEntity使用语句为:

for (int i = 0; i < repeattime; i++)
{
    RuntimeEntity.All
<Order>().LoadReaderArray();
}

Ibatis使用语句为

using (_mapper.OpenConnection())
{
    
for (int i = 0; i < repeattime; i++)
    {
        _mapper.QueryForList(
"SelectOrder"null);
    }
}

(SELECT * FROM Orders , 结果映射到一个普通的POCO中)

结果使用的时间是
RuntimeEntity 5.136 秒
IbatisMapping 9.822 秒

结论 : 读取较多记录时 , RuntimeEntity读取数据的性能是IbatisMapping的 2 倍左右.

如果把语句改为:

RuntimeEntity.All<Order>().Where("OrderId=10555").LoadReaderArray();

_mapper.QueryForObject(
"SelectOrder"10555);

运行 20000 次
结果使用的时间是
RuntimeEntity 3.169 秒
IbatisMapping 3.985 秒

结论 : 读取一条记录时 , RuntimeEntity读取数据的性能是IbatisMapping的 1.25 倍左右.

 


初步结论:

RuntimeEntity读取数据的性能是Ibatis的 1.25到2 倍,

同样是使用Lambda, RuntimeEntity读取数据的性能是Linq2SQL的 5到10 倍.

RuntimeEntity手写SQL的性能 是 DLINQ使用CompiledQuery时的 2到6 倍 (纯Mapping的对比).

注意:结论中的对比,并不能反映实际的应用.因为实际应用中数据库的查询操作的耗时将占更重的比例.这时候性能的差别就会变得更少.

补充 与DLINQ 的CompiledQuery的对比:
情况 耗时 备注
RuntimeEntity 简单条件 1052
复杂条件 4528 编译SQL用了3.5秒
Linq To SQL 简单条件 10627
复杂条件 44512 编译SQL用了40秒
Linq To SQL
预先编译
简单条件 4465 Mapping的过程依然慢
复杂条件 4884
另外说一下, 上面说的编译复杂条件的SQL在整个耗时占的比重太大的情况,
其实只是因为重复查询同一个SQL才出现这个结果.
在实际应用中会因为条件参数的不同而导致数据库服务器那边需要耗更长的时间去查询.
所以在实际应用中编译复杂条件的SQL的比重会更少.


再继续补充 , 现在RuntimeEntity新增加了一个CompileSql的方法, 目的是和CompiledQuery一样!

string compilesql = RuntimeEntity.All<Product>().CompileSql(p => p.UnitPrice > price && p.Supplier.City == city);
for (int i = 0; i < repeattime; i++)
{
    RuntimeEntity.All
<Product>().Where(compilesql,price,city).LoadReaderArray();
}




posted on 2007-11-26 02:18 Lostinet 阅读(2293) 评论(29)  编辑 收藏 网摘

评论

#1楼 [楼主]   回复  引用  查看    

WhereSql和LoadReaderArray是新加的方法.
在 RuntimeEntityPreview 能下载的那个版本中, 并不包含.

WhereSql可以使用Linq的语法代替:
var q=from p in RuntimeEntity.All < Product > ().LinqSource
where p.UnitPrice > price && p.Supplier.City == city
select p;
但是这个q无法使用LoadReaderMode, 所以无法做性能上的对比.


LoadReaderArray可以这样代替:
RuntimeEntityQuery< Product > query = RuntimeEntity.All < Product > ();
query.SetLoadReaderMode();
query.ToArray();


LoadReaderMode的目的是不使用内置的缓存.
2007-11-26 02:26 | Lostinet      

#2楼    回复  引用  查看    

我个人觉得Linq To SQL 只适合轻量级运用

虽然其语法灵活
2007-11-26 09:20 | Enzo      

#3楼    回复  引用    

楼主是怎么测试的,最近客户让我们做个简单的项目,就是给他们做个调查统计,因为时间比较近,就临时采用dlinq,数据库游7万多条,在4-6个表间的联合查询感觉都是在毫秒之间,速度相当快啊
2007-11-26 09:39 | 奇怪 [未注册用户]

#4楼    回复  引用    

RuntimeEntityGenerator有问题
连接数据库有问题
连接字符串为:
Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword
数据库为:sql2005
错误信息:
对象名“sysproperties”无效
----------------------------------------------------
具体的错误信息不能发,原因:“评论内容被系统认为是垃圾广告,不允许发布!”
2007-11-26 09:48 | 5254341 [未注册用户]

#5楼    回复  引用    

在比较生成sql语句速度呀?
2007-11-26 10:01 | dominic [未注册用户]

#6楼    回复  引用  查看    

it's amazing
2007-11-26 10:03 | 木野狐(Neil Chen)      

#7楼    回复  引用  查看    

这个比较不用说,linq to sql 慢是在构造lambda上,这个问题上次已经讨论过,像这样的重复查询,先将lambda 编译后,再测试一下吧

找了一下,原来的讨论在这里
http://www.cnblogs.com/blusehuang/archive/2007/07/09/811075.html
2007-11-26 10:08 | jjx      

#8楼    回复  引用  查看    

LINQ to SQL 号称只比DataReader慢15%。

楼主不知道怎么测的?
2007-11-26 10:13 | Ariel Y.      

#9楼    回复  引用  查看    

应该编译后再运行
不然时间都花在构造过程了,执行部分反而是小头
2007-11-26 10:19 | 补丁      

#10楼    回复  引用  查看    

正在用IBatis.net,觉得还是非常不错的,效率方面还没有碰到大问题
2007-11-26 11:22 | Clark Zheng      

#11楼 [楼主]   回复  引用  查看    

@5254341

因为SQLSERVER2005重新命名了那个系统表.
所以会有错误.
我临时屏蔽了对那个表的访问, 请重新下载测试.
2007-11-26 11:49 | Lostinet      

#12楼    回复  引用  查看    

很怀疑这个测试的准确性唉……
2007-11-26 12:11 | Jeffrey Zhao      

#13楼 [楼主]   回复  引用  查看    

@Enzo
现在RuntimeEntity也可以使用lambda甚至是linq的语法.

@奇怪
这里的快和慢的结论 , 只是一个对比. 但其实大家都已经很快.


@dominic
同样是生成SQL, RuntimeEntity明显要快很多.
但即使在简单的条件的情况下, 影响速度的还有把数据转换为Entity的过程.
所以与DLINQ的对比结果会根据不同的情况变化.

@jjx
果然是. 初初我认为RuntimeEntity的Mapping会比DLINQ快很多.
但是我使用你给的地址里的方法测试了一下:
var cq = System.Data.Linq.CompiledQuery.Compile(
(LinqNorthwind.NorthwindContext nc)=>nc.Products.Where(p => p.UnitPrice > price && p.Supplier.City == city));
RuntimeEntity 4.423秒
Linq To SQL 4.884秒
才发现性能只相差10%了!

如果是对比 p => p.ProductID<3 这个简单情况 , 即使给DLINQ进行预先编译:
RuntimeEntity 1.028秒
Linq To SQL 4.465秒

当然RuntimeEntity并没有优化生成SQL的过程.
既然DLINQ提供了, 那么这个10%的结果也算是公平的.
虽然把条件单独写开会非常麻烦, 但是我想也是应该给RuntimeEntity实现同样的方案才行.

从上面的结果依然可以看到, DLINQ进行Mapping的性能依然比RuntimeEntity慢上4倍.


@Ariel Y.
从来就不相信DLINQ的那句广告词.

@补丁
正如上面所列的情况, 如果是简单的条件语句, DLINQ依然不够快.

@Clark Zheng
是的.
如果不是对性能有十分苛刻的要求,
使用什么方法去访问数据库,
基本是以方便快捷为主了.
我个人觉得Ibatis需要写太多配置文件,很麻烦.

2007-11-26 12:13 | Lostinet      

#14楼 [楼主]   回复  引用  查看    

@Jeffrey Zhao

呵呵.
有兴趣的话可以下载RuntimeEntityPreview试试.
反正现在东西是放出来的.


2007-11-26 12:16 | Lostinet      

#15楼    回复  引用    

纯是路过
2007-11-26 12:26 | test111 [未注册用户]

#16楼    回复  引用  查看    

简单条件还差4倍?不应该呀,10%的倒是差不多。
2007-11-26 12:59 | Boler Guo      

#17楼    回复  引用  查看    

有点怀疑,因为直接用SqlDataReader的话 也就差距1倍左右
2007-11-26 14:09 | 紫色阴影      

#18楼    回复  引用    

微软东西一向是大而全,可能为了某些方面而损失性能,这两天正想学以下,适当的应用到新项目中
2007-11-26 15:05 | gxh9731 [未注册用户]

#19楼    回复  引用  查看    

请问一下,测试时iBatisNet是跑在反射优化模式下吗?
2007-11-26 15:46 | omnislash      

#20楼    回复  引用  查看    

linq to sql内建object tracking机制,这样它可以getchangeset或是在多层环境中进行attach ,虽然我试过关闭objecttracking只有很小的性能差异,但如果RuntimeEntityPreview 没有类似的机制的话,用来比较可能不是很合适.不清楚runtimeentitypreivew 和linq to sql的功能性对比,这种东西只有在功能接近或类似的情况下 才有比较的意义
2007-11-26 16:22 | jjx      

#21楼 [楼主]   回复  引用  查看    

@omnislash
IBatis默认是优化的.
现在已经提供了IBatis的测试工程的下载. 欢迎测试.

@jjx:
RuntimeEntity内置对象缓存,对象状态和属性同步机制.
这些特征在测试中也是浪费掉的.

2007-11-26 16:31 | Lostinet      

#22楼    回复  引用  查看    

--引用--------------------------------------------------
Lostinet: @Ariel Y.
从来就不相信DLINQ的那句广告词.
--------------------------------------------------------

感觉你也开始做广告了呵呵,不过我觉得, Linq比一般程序员写的慢,这是必然的~ 即使是这样,大家也会选择Linq。

关键还是用户信任的问题。微软肯定也有BUG,不过一般的框架给人的感觉只能是更不可靠。 谁都怕赶上那点几率, 如果是广泛应用的框架, 碰到什么问题, 社区里一般别人也碰到过,而且往往已经解决了,毕竟用户基数大。而第三方框架就没有这个优势,这才是一般人不会选择第三方框架的原因, 除非其他优势特别突出。

如果你真打算卖这个东西,这是不得不考虑的。另外想说的一点是, 比如我是个第三者, 我不会认为LZ比微软或者IBatis的程序员强(都这么用功,难道会有什么真的水平差距么?),即使你给出这个结果,我的想法会是什么呢? 我会认为微软或者其它框架的程序员另有考虑,所以牺牲了效率, 即使我不知道他们的考虑是什么(甚至没有,就是没写好就比你慢)。

这个心理仔细分析造成的结果就是, 你的运行效率越高, 我越不敢用, 我总感觉你快是不正常的。 反正做产品的话,有一大堆问题, 技术倒是其次的, 这些LZ可得好好琢磨~
2007-11-27 03:27 | 怪怪      

#23楼    回复  引用  查看    

好像你发布的项目版本是编译过的吧.
预编译后应该没有多大差别吧.
Linq To SQL
预先编译 简单条件 4465 Mapping的过程依然慢
复杂条件 4884

RuntimeEntity
简单条件 1052
复杂条件 4528 编译SQL用了3.5秒
2007-11-27 08:47 | winnerzone      

#24楼 [楼主]   回复  引用  查看    

@winnerzone :

RuntimeEntity也有手写的版本,后来甚至加上了预编译的支持.
只不过是没有必要写出来了.
后来我已经补充, 即使大家都是预先编译的,
RuntimeEntity依然是DLINQ的 2到6 倍.

我觉得这样比较没太大意思.
因为实际开发中, 没有人会这么有心情写预编译代码的.

当然如果项目后期需要优化程序的时候, 预编译是很有用的.
所以RuntimeEntity现在也提供了一个CompileSql方法.



@怪怪
你说的话都挺有POINT的.
不过我不是上来宣传的. 否则我早就把准备好的教程之类的东西放上来了.

发这帖的主要目的就是分享我的心得. 让大家在思想上能有个冲击.
冲击我想是有的. 不少人把IBatis当神拜. 认为手写SQL肯定是最快的.
但是到现在竟然没有人问我到底是如何实现的?
竟然没有人对一些超出他们想象的东西产生好奇心?到底是为什么?
不过如果有人进来看完这帖, 觉得有点收获, 那发这帖已经算有意义了.

其实RuntimeEntity比IBatis,DLINQ快当然有着理论上的因素.
这也是我不会称RuntimeEntity为一种ORM框架的原因.

正如你说MS拥有庞大的技术背景能保证产品的稳定性.
DLINQ还更加是DotNet3.5中最重要的部分.
这个东西一定非常好的了.
但是它是不是最好的呢? 是不是能适合每一个人, 每一个场合呢?

RuntimeEntity它面临的局势比较麻烦.
它基于DotNet2.0,但是却晚生了2年.
它需要大量用户去保证它的稳定性,和帮助推广它.
可惜我又不愿意开源.

因为我希望自用. 它有多好只有我自己知道.
有时我还有一种做ERP的冲动.
因为我有了一个强大的框架去节省我一半的编程时间.
我突然觉得我如果做ERP开发会多了一种强大的竞争力.

说真的我就是有一种纯粹利益的想法,或者说是自私的想法在心头.
我不想我推广了这个东西给其他人,得不到任何好处,
过些日子反而让其他人拿着它和我竞争.

所以最近我只会把一些技术上的心得帖上来.
帖得隐讳点. 只能说, 心得只想分享给有心人.



2007-11-27 12:44 | Lostinet      

#25楼    回复  引用    

个人觉得,没有必要关注 1.25 倍的性能,这点损失对于数据库操作的耗时来说可以忽略。
2007-11-27 17:43 | quit_game [未注册用户]

#26楼    回复  引用  查看    

"帖得隐讳点. 只能说, 心得只想分享给有心人. " --或许关注这些才是更重要的,不过做框架的人比较少数点,应用框架的人比较多点,所以Lostinet大哥要做好心理准备,^_^
2007-11-28 09:36 | 浪子      

#27楼    回复  引用  查看    

@Lostinet
抱歉, 这么晚才来回复.

看来你性格上和我有相似的地方. 但是这个问题2个月前我想通了, 人家拿咱们的东西和咱们竞争, 这其实是一个好事. 最怕的是出现聪明人, 拿一样有竞争力的自主研发的东西和咱们竞争, 因为我们只能知道自己的思路, 无法提前预知别人的思路. 但是那些抄袭的家伙, 可以说他们即使也很聪明, 他们的道路也因为咱们第一步的工作会变窄, 是可以预期的.

恰恰相反, 这些拿咱们的东西参与到竞争力的人, 会帮助咱们集思广益, 这是其一; 其二是, 他们的出现, 对咱们的打击要小于对咱们的独立竞争对手的打击. 为什么呢? 因为咱们对这些人思路和发展的把握, 要超过竞争对手; 而竞争对手却不得不应付这些聪明的咱们产品的抄袭者. 当然如果他的产品够棒, 有人抄, 咱们也要应付他的那些抄袭者. 一个混战的局面, 最终下来, 如果作为起头人, 咱们和竞争对手都有足够实力, 最后剩下来瓜分市场, 是可想而知的, 甚至还可以通过给那些跟风的发认证再敲一笔.

当越来越多的产品选用我们的思路和基础去构建的时候, 我相信我们的价值也会不断增加. 关键是在道义上也站住了脚. 比如一个活, 价值一百万, 你去竞标, 一个抄你的人也去竞标, 你说我最擅长干这个, 所有人都得信, 为什么呢? 因为你可以拿出证据证明你是最先干这个的, 而且对手很有可能是抄袭你. 但是如果是两个独立的竞争对手, 尤其产品上还是具有一到两个可以明显区分的点, 哪怕竞争对手比你差, 但是客户一时分辨不出来, 这时决定的因素中技术加分, 往往是一边一半. 这个还只是表面层次的, 深层次的道理我讲不清楚.

再比如我觉得做产品不能只看眼前, 比如Lucene, 他的东西绝对公开, 很多人在用Lucene赚钱. 但是Lucene不公开的话, 这些钱他就能赚到吗? 很显然公开, 并证明自己, 让他自己本身的领域拓广开了. 他赚到了原来该赚的那一份, 他还建立了一份无形资产, 让他能投入到未来更好的竞争和赚钱.

但是, 如果中间介入一个抄袭者, 这个抄袭者的实力超强, 比如水平是我的3倍, 对这个事情也早有思路, 只是没注意到市场, 那么我被他打败, 那是理所应当的, 我对社会的贡献和使命, 很可能就是吸引他来从事这个. 那么即使我不开源, 让他看到这里有甜头, 我最后也会被他打败. 也就是说, 我最终的在该领域的竞争力和地位, 其实并不由开不开源决定, 最终还是我自身实力决定的.

当然我说咱们, 其实我还没有这个资格. 你的东西已经出了, 我的东西还是只有一半能转. 不过我做的是界面部分, 和你可不是竞争对手. 不过如果我和你是竞争对手的话, 我觉得我最好的策略就是把代码整理的象点样, 提前开源.

以前咱们程序员, 主要的挣钱方式是遇到一个伯乐, 以雇佣或劳务关系, 尽量发挥自己的价值. 到未来, 尤其是有特色的程序员, 应该会有更多的渠道. 通过处理人际关系建立自己的网, 我觉得对于技术方面投入精力决定核心竞争力的咱们来说, 不太现实. 炒作呢, 在没有资本的情况下, 只有一种手段, 就是开源, 但是花费一部分精力去保证开源后的发展状况, 为自己赢得应有的名声和影响力.

我的东西完成了, 也不打算马上开源, 因为代码还太烂, 这是唯一制约我的因素. 等到我认为我这个东西, 从源代码和架构角度讲, 一定可以作为一个较为稳定的平台了, 我就有了开源的基础.

嗯随便交流一下, 不知是否有理, 只当大家集思广益吧 :)
2007-11-30 04:00 | 怪怪      

#28楼    回复  引用  查看    

另外其实我对你这个怎么实现, 肯定敢兴趣, 但是精力有限啊...

感觉你现在有份不错的工作, 开发这些也和你的工作内容相关. 我可不是, 一边弄着一个小框架, 还得经常看哪个朋友有小忙要帮, 给口饭吃, 大忙我还舍不得花那份时间. 从MFC App之类五花八门到ASP.NET Web, 从一些没意思的需求更改来回跳到框架思路, 有的时候被打断了, 找回原来干到哪儿了都要花费不少时间, 一个字惨.

不过我对这种生活虽然不是特别有信心, 但是还是想继续下去. 在我看来, 一万两万的工资, 不是那么容易拿的, 得给人家办事, 那我自己的事情会比现在进度还慢. 而且如果不是我觉得能大展拳脚的领域, 恐怕对我和雇主的发展都没什么好处.

怎么发起牢骚了呵呵, 真羡慕你, 工作和自我发展能够合一 :)
2007-11-30 04:16 | 怪怪      

#29楼 [楼主]   回复  引用  查看    

@怪怪

就算是最近我想用RuntimeEntity做个简单的例子, 也怕会阻碍公司的新产品的发展。

你说的话提醒了我。

有时候竞争对手嘛,,真的说不定是可以合纵的伙伴。

我要重新思考一下策略才行了呵呵。

-----
另外不用怕代码烂就不开源。
我看过IBatisNet的代码,那个烂,还不是一样放出来了。

2007-11-30 13:00 | Lostinet      

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-11-26 16:29 编辑过
Google站内搜索



相关文章:

相关链接: