在看完下面的文章之前, 希望读者心里估计一下大概的情况.
也许文章里所归纳的结论, 和你想的相差非常远.
更新,提供对比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();
}