1

我们有一个使用linq to entity的网站,最近发现速度很慢,经过故障排除,我发现每当我们使用linq to entity从数据库中搜索数据时,都会消耗非常多的CPU时间,比如toList()function。我知道这可能是因为我们在数据库中有大量数据导致响应缓慢,但我只是想知道是否还有其他可能导致此问题的原因?

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

  1. ToList()可能会加载所有对象的外来对象(外键),我怎样才能强制它只加载对象?

  2. 我的连接池是否太小?

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

4

2 回答 2

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. 检查数据库中其他连接持有的锁。

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

于 2012-05-18T04:31:21.753 回答
0

您可能会在 MSDN 上的性能注意事项(实体框架)中找到问题的解决方案。尤其是

返回正确的数据量

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

为避免在单个查询中返回过多数据,请考虑将查询结果分页到更易于管理的组中。有关详细信息,请参阅如何:浏览查询结果

于 2012-05-18T08:19:23.820 回答