为什么重用DataContext会对性能产生负面影响?

经过大量 研究和一些错误后 ,我修改了我的代码,以便每次查询数据库或插入数据时都会创建一个新的DataContext。 并且经常查询数据库 – 对于处理的250k个事务中的每一个,在插入事务之前,将查询数据库以获取客户ID,部门ID和类别。

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

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

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

以下是从MSDN DataContext文档中重用DataContext不是最佳实践的原因:

DataContext是通过数据库连接映射的所有实体的源。 它跟踪您对所有检索到的实体所做的更改,并维护“身份缓存”,以确保通过使用相同的对象实例来表示检索多次的实体。

通常,DataContext实例设计为持续一个“工作单元”,但是您的应用程序定义该术语。 DataContext是轻量级的,创建起来并不昂贵。 典型的LINQ to SQL应用程序在方法范围内创建DataContext实例,或者作为表示相关数据库操作的逻辑集的短期类的成员。

如果您为大量查询重新使用DataContext,则性能会因几个原因而降低:

  1. 如果DataContext的内存中的身份缓存变得如此之大以至于它必须开始写入页面文件,那么你的性能将受到HD的读取头速度的限制,并且实际上没有理由使用缓存。

  2. 内存中的标识对象越多,每个保存操作所花费的时间就越长。

基本上你正在做的是违反DataContext类的UoW原则。

打开数据库连接确实会产生一些与之相关的开销,但保持连接长时间打开(通常也意味着锁定表)比快速打开和关闭它们更不可取。

MSDN中可能有或没有帮助的另一个链接:

如何:重用ADO.NET命令和DataContext之间的连接(LINQ to SQL)

即使使用聚簇索引,内存中查找也总是比数据库查询更快 – 除非在边缘情况下,例如386与Cray相比 – 即使您分解出与网络相关的延迟。

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

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

这里不完全是,但您是否考虑过某种应用程序级缓存来查找客户ID,部门ID和类别? 从您的post中不清楚您的系统中存在多少这些实体,或者查询获取它们涉及的内容。

但是,作为一个例子,如果您的系统中有一百万个类别,并且您需要按类别名称查找其ID,那么在内存中保留名称/ Id字典以便随时查找将为您节省数据库之旅你处理的交易。 这可以大大提高性能(这假设了一些事情,例如没有定期添加新的护理)。 作为一般规则,相对于内存操作,到数据库的往返是昂贵的。

您必须对端到端的所有内容进行分析,并查看您的时间在哪里。

如果行宽,则聚簇索引不一定是最快的。 最快的可能是覆盖非聚集索引,但这真的不是重点。

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