我需要在什么时候将查询工作卸载到数据库?

时间:2015-09-06 20:30:32

标签: c# database asp.net-mvc-4 entity-framework-6

我有一个网络应用程序,我正在使用实体框架连接到数据库。

例如,要选择特定部门的所有Employee条记录,我可以很容易地写出来:

....Employees.Where(o => o.Department == "HR").ToList();

工作正常。但这是最优化的吗?

是否应将此Where子句合并到存储过程或视图中?或者我的实体框架代码是否完成了将其转换为SQL的工作?

我们团队过去遇到了性能问题,因为人们将记录拉入内存并且然后在.net而不是数据库级别进行过滤。我试图再次避免这种情况发生,所以想要明确我必须避免的事情。

2 个答案:

答案 0 :(得分:1)

如果实体框架提供了Employees,那么Where()将被翻译成SQL并发送到数据库。只有这样才能实现对象是否需要使用之前应用的过滤器并将它们转换为SQL。在那一点之后的任何事情都只是对象的简单LINQ。

导致实现的方法包括.ToList().ToArray()(还有更多,但这两种可能是最常见的)。

如果要查看SQL Server上发生的情况,您应该打开SQL事件探查器并查看正在发送的查询。

答案 1 :(得分:1)

  

过去我们的团队遇到了性能问题,当时人们将记录拉入内存,然后在.net而不是数据库级别进行过滤。

正如对Colin的回答的补充,并且针对上面的引用,避免这种情况的方法是在使用诸如调用之类的调用枚举结果之前,确保首先使用IQueryable<T>完全构造数据库查询。 .ToList().ToArray()

例如,请考虑以下事项:

IEnumerable<Employee> employees = context.Employees;
// other code, before executing the following
var hrEmployees = employees.Where(o => o.Department == "HR").ToList();

.ToList()将首先从上下文中列出抓取所有员工的结果,然后在客户端上执行过滤。如果你有很多员工需要应对,这种情况就不会很好,而且肯定不会很好地扩展。

与此相比:

IQueryable<Employee> employees = context.Employees;
// other code, before executing the following
var hrEmployees = employees.Where(o => o.Department == "HR").ToList();

IQueryable<T>来自IEnumerable<T>。它们之间的区别在于IQueryable<T>内置了查询提供程序,您构造的查询表示为表达式树。这意味着在枚举查询结果的调用(例如.ToList())之前不会对其进行评估。

在上面的第二个示例中,查询提供程序将执行SQL以仅获取属于HR部门的员工,对数据库本身执行过滤。