为什么在linq中将.ToList()耗费给实体?

时间:2012-05-18 01:59:00

标签: c# asp.net-mvc linq linq-to-entities

我们有一个使用linq实体的网站,我们发现它最近很慢,经过故障排除后,我发现每当我们使用linq实体从数据库中搜索数据时,它会消耗很多CPU时间,比如{{ 1}}功能。我知道这可能是因为我们在数据库中有大量数据会导致响应变慢,但我只是想知道是否还有其他可能导致此问题的原因?

如何优化这些问题呢?以下是可能的原因:

  1. toList()可能会加载所有对象的外来对象(外键),如何强制它只加载对象?

  2. 我的连接池太小了吗?

  3. 如果还有其他可能的原因,请告诉我,并指出正确的方向来解决这个问题。

2 个答案:

答案 0 :(得分:5)

在Linq中 - 查询会在枚举查询时将一系列操作的结果返回到

IQueryable<Customer> myQuery = ...

foreach(Customer c in myQuery)  //enumerating the query causes it to be executed
{

}

List<Customer> customers = myQuery.ToList();
  // ToList will enumerate the query, and put the results in a list.
  // enumerating the query causes it to be executed.

执行查询需要一些事情(没有特别的顺序)

  • 从池中提取数据库连接。
  • 查询由查询提供程序解释(在这种情况下,提供程序是实体的linq,解释是某种形式的sql)
  • 将解释后的表单传输到数据库,然后执行它所做的操作并返回数据对象。
  • 必须生成一些方法将传入的数据对象转换为所需的查询输出。
  • 将数据库连接返回到池中。
  • 在返回到您的代码之前,所需的查询输出可能会对其进行状态跟踪。

此外,数据库有几个步骤,这里是从查询sql server的角度列出的:

  • 接收查询文本,并根据现有计划的查询计划缓存进行检查。
  • 如果不存在计划,则会创建一个新计划并由查询优化程序插入计划缓存中。
  • 执行查询计划 - IO / locks / CPU / Memory - 其中任何一个都可能成为瓶颈
  • 返回查询结果 - 网络可能是瓶颈,特别是如果结果集很大。

所以 - 要找出查询问题的位置,您需要开始测量。我会按照我检查的顺序订购这些目标。这不是一个完整的清单。

  1. 获取查询的已翻译sql文本。您可以使用sql server profiler。您可以使用调试器。有很多方法可以解决这个问题。确保查询文本返回对象所需的内容,不多也不少。确保查询的表符合您的期望。运行查询几次。

  2. 查看结果集。这是合理的还是我们正在寻找500 Gigs的结果?当整个事情不需要时,是否会查询整个表格?是否意外地产生了笛卡尔结果?

  3. 获取查询的执行计划(在sql studio中,单击show estimated execution plan按钮)。查询是否使用您期望的索引?该计划看起来很糟糕(可能是一个糟糕的计划来自缓存)?查询是否按照您期望的顺序在表上工作,并以您期望的方式执行嵌套/合并/散列连接?是否存在并行化,当查询不值得时(这是错误索引的标志/ IO的TONS)?

  4. 测量查询的IO。 (在sql server中,发出SET STATISTICS IO ON)。检查每个表的逻辑IO。哪张桌子突出?再次,查找表访问的错误顺序或可以支持查询的索引。

    如果你已经做到这一点,你很可能找到并修复了问题。我会坚持下去,万一你还没有。

  5. 将查询的执行时间与枚举的执行时间进行比较。如果存在很大差异,则可能是解释数据对象的代码很慢或生成缓慢。也可能是查询的翻译需要一段时间。这些都是棘手的问题需要解决(在LinqToSql中我们使用编译的查询对它们进行排序)。

  6. 测量代码运行的机器的内存和CPU。如果您受限,请使用代码分析器或内存分析器来识别并解决问题。

  7. 查看计算机上的网络统计信息,特别是您可能希望使用TCPView查看计算机上的TCP套接字连接。套接字资源可能被误用(例如在一分钟内打开和关闭数千个)。

  8. 检查数据库是否有其他连接所持有的锁。

  9. 我想这就够了。希望我没有忘记任何明显的事情要检查。

答案 1 :(得分:0)

您可以在MSDN上的Performance Considerations (Entity Framework)中找到问题的解决方案。特别是

  

返回正确的数据量

     

在某些情况下,使用Include方法指定查询路径是   更快,因为它需要更少的往返数据库。   但是,在其他情况下,额外往返数据库往返   加载相关对象可能会更快,因为更简单的查询   连接越少,数据冗余越少。因此,我们   建议您测试各种检索方式的性能   相关对象。有关详细信息,请参阅Loading Related Objects

     

为避免在单个查询中返回过多数据,请考虑分页   查询到更易管理的组的结果。更多   信息,请参阅How to: Page Through Query Results