2010-07-13 110 views
13

之后fairamountofresearchresearch和一些errors,我修改了我的代码,以便它在每次查询数据库或插入数据时创建一个新的DataContext。并且经常查询数据库 - 对于处理的每个250k事务,在插入事务之前查询数据库以获取客户ID,部门ID和类别。为什么重复使用DataContext会对性能产生负面影响?

所以现在我试图优化代码,因为它每秒只能处理大约15个事务。我删除了一些无关的查询并添加了一些索引,并将其提高到30 /秒。然后我发现即使每个人都说DataContext是轻量级的,但每次事务都需要花费一些时间来创建一个新的,所以我尝试重用DataContext。我惊奇地发现,重用上下文会导致性能每秒降低10个事务!

为什么会这样?是因为DataContext将实体缓存在内存中,并且在查询数据库之前首先搜索其内存列表中的实体?因此,例如,如果我正在寻找名称为“MCS”的客户的客户id(主键),并且客户名称列上有一个聚集索引,以便数据库查询速度很快,则内存查找会更慢?

确实,创建/配置如此之多的数据库连接会降低速度,或者这只是另一个过早的优化?如果它是真的,有没有办法重用一个DataContext,但让它为每个linq-to-sql查询执行实际的数据库查询?

回答

12

这也是为什么重新使用的DataContext是不是最好的做法,从MSDN DataContext documentation

DataContext的是映射在一个数据库连接 所有 实体的来源。 它跟踪您对所有检索到的实体做出的更改 维护一个“身份缓存”, 保证检索到的实体 不止一次由 表示使用同一对象实例。

一般来说,一个DataContext实例 设计寿命为一个“ 工作单位”但是你的应用程序定义 这个词。一个DataContext是 轻量级,并且对于 创建并不昂贵。典型的LINQ to SQL 应用程序在方法范围创建DataContext 实例或作为 代表相关 数据库操作的逻辑集的短命类成员。

如果您正在重新使用一个DataContext了大量的查询,你的表现会降低了几个可能的原因:

  1. 如果DataContext的的内存标识缓存变得如此之大它必须开始写入页面文件,然后你的性能将被绑定到HD的读取头速度,并且根本没有理由使用高速缓存。

  2. 内存中的标识对象越多,每次保存操作所需的时间越长。

基本上你在做什么违反了DataContext类的UoW原则。

打开数据库连接确实有一些相关的开销,但保持连接打开很长一段时间(这通常也意味着锁定一张表)比快速打开和关闭连接更不可取。

可能会或可能不会帮助你从MSDN另一个链接:

How to: Reuse a Connection Between an ADO.NET Command and a DataContext (LINQ to SQL)

1

即使使用聚簇索引,内存查找始终会比数据库查询更快 - 除边缘情况外(如386与Cray),即使您将网络相关延迟分解出来。

我猜想退化与DataContext对其跟踪的实体的处理有关:重用上下文将不断增加跟踪实体的数量,并且对SaveChanges的调用可能最终需要更多时间。

再一次,这是一个猜测 - 但它是我开始寻找的地方。

1

你将不得不简介一切结束到终端的,看看你的时间是真正花在哪里。

如果一行很宽,聚集索引不一定是最快的。最快的可能是一个覆盖的非聚集索引,但这确实没有意义。

我希望为了获得更多的性能,如果你没有真正使用这些功能,你可能不得不抛弃一些框架。如果你正在使用这些功能 - 那么,这就是你正在付出的代价...

1

不完全在这里,但你有没有考虑某种应用级缓存来查找客户ID,部门ID和类别?从您的文章中不清楚您的系统中存在多少这些实体,或者查询获取这些实体时涉及的是什么。例如,如果您的系统中有一百万个类别,并且您需要按类别名称查找他们的ID,那么始终在内存中保留一个名称/ Id字典以便随时查找,这将为您节省一笔旅行到数据库处理您的事务。这可以大幅度提高表现(这假定有几件事情,比如新护理不会定期添加)。作为一般规则,相对于内存操作而言,往返数据库的成本较高。

相关问题