我正在尝试确定实体框架比存储过程慢多少。我希望说服我的老板让我们使用Entity Framework来简化开发。
问题是我进行了性能测试,看起来EF比Stored Procs慢大约7倍。我觉得这很难相信,我想知道我是否遗漏了什么。这是一个确凿的测试吗?有什么办法可以提高EF测试的性能吗?
var queries = 10000;
// Stored Proc Test
Stopwatch spStopwatch = new Stopwatch();
spStopwatch.Start();
for (int i = 0; i < queries; i++ )
{
using (var sqlConn = new SlxDbConnection().Connection)
{
var cmd = new SqlCommand("uspSearchPerformanceTest", sqlConn) { CommandType = CommandType.StoredProcedure };
cmd.Parameters.AddWithValue("@searchText", "gstrader");
sqlConn.Open();
SqlDataReader dr = cmd.ExecuteReader();
List<User> users = new List<User>();
while (dr.Read())
{
users.Add(new User
{
IsAnonymous = Convert.ToBoolean(dr["IsAnonymous"]),
LastActivityDate = Convert.ToDateTime(dr["LastActivityDate"]),
LoweredUserName = dr["LoweredUserName"].ToString(),
MobileAlias = dr["MobileAlias"].ToString(),
UserId = new Guid(dr["UserId"].ToString()),
UserName = (dr["UserName"]).ToString()
});
}
var username = users.First().UserName;
sqlConn.Close();
}
}
spStopwatch.Stop();
Console.WriteLine("SP - {0} Queries took {1}", queries, spStopwatch.ElapsedMilliseconds );
// EF Test
Stopwatch entityStopWatch = new Stopwatch();
var context = new SlxDbContext();
var userSet = context.Set<User>();
entityStopWatch.Start();
for (int i = 0; i < queries; i++)
{
User user = userSet.Where(x => x.UserName == "gstrader").First();
}
entityStopWatch.Stop();
Console.WriteLine("Entity - {0} Queries took {1}", queries, entityStopWatch.ElapsedMilliseconds);
结果:
SP - 10000查询占用了2278
实体 - 10000查询占用16277
您可以执行一些操作来优化查询。 Here on MSDN你可以找到一个很好的概述。
但说实话,具有手动映射的存储过程的性能总是更快。但问问自己,表现有多重要?在大多数项目中,开发时间比性能更重要。什么难开发?具有解析或实体框架查询的原始查询?
ORM的设计并不是因为它们比手写方法表现得更好。我们使用它们因为开发更容易!
如果您使用实体框架编写应用程序并隐藏存储库模式背后的所有查询,则可以快速开发,然后在性能成为问题时,测量应用程序以检测瓶颈。然后,您的某些查询可能需要优化,并且可以移动到存储过程和手动映射。
与@Wouter de Kort达成协议......此外,当您需要转移到程序时,您可以将EF与程序结合使用以协助从一个程序迁移到另一个程序。
如果您将功能统一到设计良好的过程中,那么在典型应用程序中迁移到过程会更快。即尽可能多地在一个sproc调用中完成工作。例如,在用户单击结帐按钮的购物车MVC应用程序中,您可以将ORM用于以下内容:
或者它可能是完全不同的步骤,但无论如何,重点是,MVC应用程序将使用ORM对DB进行多次调用以进入下一步。
如果所有这些逻辑都封装在一个编写良好的sproc中,那么只有一个调用sproc并且你已经完成了。使用MVC-ORM路由,必须将数据从数据库复制到驱动程序并传送到ORM(通常通过网络传送到不同的主机),然后由MVC应用程序读取以做出简单的决定然后重复,直到所有步骤完成。在使用封装该签出步骤的sproc的情况下,复制和移动的数据少得多,网络IO少,上下文切换少等。
以这种方式考虑MVC-ORM解决方案。人“A”只知道事实,而“B”则具有所有精明的知识,可以用他没有提出的既定事实作出决定。人“B”以事实形式发送电子邮件“A”。根据“A”的答案,“B”可能会在做出决定之前要求更多的事实。这是很多来回传递的消息。
如果你有一个人拥有所有事实和知识来做出决定,你只需要提出一个问题,他们的大脑会在内部处理所有事情以得出答案。不涉及与他人的商议。当然它会更快。
这并不是说它必然更好。将事实与决策分开意味着这些组件可以单独替换/测试,但是,如果您与MVC和您的数据库结婚,那么这是一个“非问题”。
另一方面,许多MVC粉丝讨厌编写SQL,因此他们考虑将任何决策逻辑放入SQL作为自然灾害。对于这样的人来说,必须使用与MVC相同的语言编写任何逻辑,因为它加速了它们的开发。在某些情况下,这也是一个“非问题”,因为在某些RDMBS的情况下,您可以使用与MVC使用的语言相同的语言编写sprocs(示例:.Net - SQL Server sprocs可以用C#编写并使用.Net; Postgresql函数(没有sprocs)可以用Perl,Python,PHP等编写。)这种情况下的优点是你可以拥有快速的sprocs,在一次调用中封装多个步骤,你可以使用一种编程语言已经快速编码了。
重要的是要注意到这一点
从.NET Framework 4.5开始,LINQ查询会自动缓存。但是,您仍然可以使用已编译的LINQ查询在以后的执行中降低此成本,并且编译的查询可以比自动缓存的LINQ查询更有效。